diff --git a/Documentation/Soar8Manual.pdf b/Documentation/Soar8Manual.pdf
new file mode 100644
index 0000000..288e829
Binary files /dev/null and b/Documentation/Soar8Manual.pdf differ
diff --git a/Documentation/TutorialPart1.pdf b/Documentation/TutorialPart1.pdf
new file mode 100644
index 0000000..8092303
Binary files /dev/null and b/Documentation/TutorialPart1.pdf differ
diff --git a/Documentation/TutorialPart2.pdf b/Documentation/TutorialPart2.pdf
new file mode 100644
index 0000000..98d0edf
Binary files /dev/null and b/Documentation/TutorialPart2.pdf differ
diff --git a/Documentation/TutorialPart3.pdf b/Documentation/TutorialPart3.pdf
new file mode 100644
index 0000000..67269b2
Binary files /dev/null and b/Documentation/TutorialPart3.pdf differ
diff --git a/Documentation/TutorialPart4.pdf b/Documentation/TutorialPart4.pdf
new file mode 100644
index 0000000..22a28ab
Binary files /dev/null and b/Documentation/TutorialPart4.pdf differ
diff --git a/Documentation/TutorialPart5.pdf b/Documentation/TutorialPart5.pdf
new file mode 100644
index 0000000..8167b69
Binary files /dev/null and b/Documentation/TutorialPart5.pdf differ
diff --git a/Documentation/TutorialPart6.pdf b/Documentation/TutorialPart6.pdf
new file mode 100644
index 0000000..7a2e807
Binary files /dev/null and b/Documentation/TutorialPart6.pdf differ
diff --git a/Documentation/soar7-to-soar8.txt b/Documentation/soar7-to-soar8.txt
new file mode 100644
index 0000000..5eda6b8
--- /dev/null
+++ b/Documentation/soar7-to-soar8.txt
@@ -0,0 +1,77 @@
+ List of changes required in upgrading from Soar 7 to Soar 8.
+ John E. Laird
+ December 11, 1998
+
+This document list the changes that have to be made to Soar 7 programs
+so that they run under Soar 8.
+
+1. All preferences in attributes are eliminated. Soar 8 uses
+ preferences exclusively for the selection of operators.
+ A. Previous use of preferences such as best (>) and worst (<) for
+ values of attributes to create defaults must be eliminated. You
+ may need to add operators to select the values of these attributes
+ explicitly.
+ B. Parallel preferences (&) are no longer needed to allow
+ multi-valued attributes - attributes that have more than one value
+ in working memory. All attributes (except the operator attribute
+ of a state) can have multiple values.
+ C. There are no longer any attribute impasses.
+
+2. The order of input, decision, and output has changed. The new
+ordering is:
+
+ input -> operator propose -> decision -> operator apply -> output
+ ^ i-support o-support & |
+ | i-support |
+ --------------------------------------------------------------
+
+ A. Input is called only once per decision.
+ B. Output is called only once per decision.
+ C. Only rules that create i-supported structures fire during the
+ operator propose phase. Rules fire in parallel and to quiescence.
+ D. During the operator apply phase, all matched rules fire in
+ parallel and to quiescence.
+ These changes do not necessarily lead to any change in your software,
+ and may even allow you to simplify your software.
+
+3. Selected operators are removed (the ^operator working memory
+ element is removed) as soon as the operator either no longer has an
+ acceptable preference, or if it would not stay selected because of
+ changes in the preferences. A new operator is selected only during
+ decision (thus, there may be parts of the cycle in which no operator
+ is selected).
+
+ This process replaces the reconsider preference for operators - Soar
+ 8 does not support reconsider. You will need to remove all of the
+ rules that create reconsider preferences (terminate*operator rules).
+
+ You may need to ``tweak'' the conditions of your proposals so that an
+ operator is not removed too early or too late. You may also need to
+ split an operator that created or changed many internal data
+ structures in sequence into separate operators because the operator
+ will probably be retracted as soon as the first data structure is
+ modified (which will probably cause the operator proposal to
+ retract).
+
+4. Goals (substates) are automatically retracted if any of the
+ o-supported structure in them become ``inconsistent'' with higher
+ levels of the goal/state stack. A goal with o-supported structure is
+ removed if any of the working memory elements in higher level
+ goals/states that were tested along the path to creating the
+ o-supported structure are removed.
+
+ The easiest thing to do in response to this change is move
+ o-supported structures up to the top-level state.
+
+5. Dot notation is legal in actions.
+
+Some other changes that aren't required, but might be nice to note:
+
+1. RHS dot notation
+2. Ability to run til agent produces output
+3. Some ONCs are "free" (detected immediately, without extra decision cycles)
+
+In the section on the new decision cycle, we should indicate that
+the TSI includes a facility to allow users to stop after the decision
+phase. We could also include the info needed to set up callbacks
+after the decision phase.
diff --git a/Soar Suite 8.5.2 Release Notes.txt b/Soar Suite 8.5.2 Release Notes.txt
new file mode 100644
index 0000000..40e076c
--- /dev/null
+++ b/Soar Suite 8.5.2 Release Notes.txt
@@ -0,0 +1,185 @@
+ Summary of changes between SoarSuite 8.5.1 and SoarSuite 8.5.2
+ July, 2004
+
+
+A summary of changes in SoarSuite 8.5.2 is listed immediately below. For more
+details, including changes not mentioned in the summary and a list of known
+issues see the Details section after the summary.
+
+======================
+New Windows Installer:
+======================
+
+ The Windows installer is now built with a different technology which
+is much easier for us and results in a much smaller package.
+
+=========================
+Several kernel bug fixes:
+=========================
+
+ Almost all known bugs fixed, including all known crash bugs. See the
+details section below for more information.
+
+==================
+New TankSoar Bots:
+==================
+
+ TankSoar now comes with two new bots. Mapping-bot demonstrates how a
+tank might build up an internal map of the level. Obscure-bot is a challenge bot
+for people to test their own bots against. The code is provided in an obfuscated
+binary. See obscure-bot.txt in the TankSoar agents directory for details.
+
+==========================
+SoarDoc and DMGen updated:
+==========================
+
+ These changes were actually in the the 8.5.1 release, but we failed
+to note them.
+SoarDoc:
+ - Fixed special character handling when UseExistingComments is used.
+ - Added ShowProdSourceInline which shows production source code
+ inline in the production documentation
+ - Ability disable datamap node coloring
+ - Fixed case-sensitivity issues for production names and list sorting.
+DMGen:
+ - Fixed handling of mixed-case production names.
+
+======================
+Documentation Updated:
+======================
+
+ The tutorials have had some typo fixes and screenshot updates, and also
+explain substates better.
+
+==================
+Tcl Soar Debugger:
+==================
+
+ The TSDebugger has several bug fixes which may have affected some
+users.
+
+===================
+VisualSoar Updated:
+===================
+
+ VisualSoar has several small bug fixes.
+
+======================
+Critical SGIO bug fix:
+======================
+
+ Our fix for bug 254 in the last release actually caused serious
+problems. This has been fixed for real now.
+
+====================================================================
+ Details
+====================================================================
+
+Below is a fairly complete list of enhancements, changes, bug fixes, and known
+issues, with bug numbers for reference. For more information and up to date list
+of what's been fixed please visit the Soar bugzilla server at:
+
+ https://winter.eecs.umich.edu/soar-bugzilla/.
+
+New bug submissions and enhancement requests are welcome!
+
+
+Soar-8.5.2
+==========
+
+Bug Fixes
+---------
+353 stats command keeps recording between runs
+389 missing error handling for set_watch_prod_group_setting
+
+Enhancements
+------------
+358 change soar8 command error message
+
+Known Issues
+------------
+312 agent structure isn't cleaned up properly
+356 All matches get same support as last processed match
+
+TSDebugger 4.0.1
+================
+
+Bug Fixes
+---------
+365 rules that contain a capital letter break productions tab
+376 stop button doesn't work with Eaters, TankSoar
+396 error when closing group from task bar
+398 extra 0 gets printed when soar connected to environments
+
+Known Issues
+------------
+336 negated conditions don't print properly in the console window
+397 grouping bar in production tab not always right
+
+SGIO 1.1.2
+==========
+
+Bug Fixes
+---------
+254 Some special characters in StringWME's do not transfer to Soar
+
+Eaters 3.0.8
+============
+
+Bug Fixes
+---------
+391 garbage printed to debugger output when Stop After Decision Phase is on
+
+TankSoar 3.0.8
+==============
+
+Bug Fixes
+---------
+map loading menu now defaults to maps directory
+188 Selecting Map->Random Map causes error message when agent present on
+ current map
+392 garbage printed to debugger output when Stop After Decision Phase is on
+393 command 'run 1' generates 'invalid command step' error
+
+Enhancements
+------------
+new challenge bot (obscure-bot) and mapping bot provided
+
+Known Issues
+------------
+399 can't use reset tank command in tank control panel tanks menu
+
+Documentation
+=============
+
+Bug Fixes
+---------
+349 tutorial images need to be updated
+375 typo in tutorial part 1: move-north
+386 typos in tutorial part 1 (search control)
+
+Enhancements
+------------
+Added information to tutorial about substates.
+
+Known Issues
+------------
+380 typo in section 5.6.3
+381 o-support-mode command missing newest support modes
+
+VisualSoar 4.5.3
+================
+
+Bug Fixes
+---------
+361 adding a dir that doesn't exist to agent path on file->new project fails with no warning
+362 initial rules in a project are not justified correctly
+363 if project loaded then create new project, title bar does not change
+364 file with same name as datamap have same window names
+366 Initialize- Operator not in datamap
+368 dragging node onto itself makes node disappear
+372 fails to detect extra whitespace after :
+
+Known Issues
+------------
+Too many to list. See bugzilla for details.
\ No newline at end of file
diff --git a/dmgen-1.0.0/doc/dmgen.pdf b/dmgen-1.0.0/doc/dmgen.pdf
new file mode 100644
index 0000000..e1a4265
Binary files /dev/null and b/dmgen-1.0.0/doc/dmgen.pdf differ
diff --git a/dmgen-1.0.0/license.txt b/dmgen-1.0.0/license.txt
new file mode 100644
index 0000000..2927b54
--- /dev/null
+++ b/dmgen-1.0.0/license.txt
@@ -0,0 +1,34 @@
+Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of Soar Technology, Inc.,
+the University of Michigan, or the Soar consortium.
+
diff --git a/dmgen-1.0.0/readme.txt b/dmgen-1.0.0/readme.txt
new file mode 100644
index 0000000..058a803
--- /dev/null
+++ b/dmgen-1.0.0/readme.txt
@@ -0,0 +1,5 @@
+dmgen - Soar datamap generation tool by Soar Technology, Inc.
+
+Please see doc/dmgen.doc for details on running dmgen. The
+main dmgen program script is src/dmgen.tcl.
+
diff --git a/dmgen-1.0.0/src/bwutil.tcl b/dmgen-1.0.0/src/bwutil.tcl
new file mode 100644
index 0000000..4bfc8d9
--- /dev/null
+++ b/dmgen-1.0.0/src/bwutil.tcl
@@ -0,0 +1,145 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# BWidget utilities
+#
+# A set of utilities for dealing with widgets, mostly BWidgets.
+package require BWidget
+
+namespace eval BwUtil {
+
+# Expand all the nodes in a BWidget tree widget.
+proc ExpandBWidgetTree { t } {
+ set ch [$t nodes root 0 end]
+ foreach n $ch {
+ $t opentree $n
+ }
+}
+
+# Given a graph and a start vertex, fills in a BWidget tree with
+# using the value of $field as the label of each node.
+# The tag of each tree node is the same as its corresponding vertex in the
+# graph.
+# The -data property of each tree node is filled with a 'struct' with the
+# following values:
+# BackEdges - List of adjacencies to this vertex that could not
+# be connected because they would have formed a cycle (not easy
+# to display with a tree :)
+# Here's an example of getting at this data:
+# array set data [$tree itemcget $node -data]
+# puts "Backedges = $data(Backedges)"
+#
+# @param treeName Tree widget
+# @param graph The source graph
+# @param vert The starting vertex in the graph (only child of root)
+# @param field The name of the vertex field that should be used as node
+# label. (e.g, name)
+proc NewBWidgetTreeFromGraph { treeName graph vert field } {
+ set w [Tree $treeName]
+ foreach v [$graph GetVertices] {
+ set visited($v) 0
+ }
+ set visited($vert) 1
+
+ set NV [Graph::NullVertex]
+ set L [list [list $vert $NV]]
+
+ while { [llength $L] > 0 } {
+ set vl [lindex $L 0] ;# Get head of queue
+ set L [lrange $L 1 end] ;# pop head of queue
+
+ set c [lindex $vl 0] ;#child
+ set p [lindex $vl 1] ;#parent
+ if { $p == $NV } { set p root }
+
+ $w insert end $p $c -text [$graph Get $c $field]
+ set be {} ;# accumulate back edges
+ foreach v [$graph GetOutAdjacencies $c] {
+ if { !$visited($v) } {
+ set visited($v) 1
+ lappend L [list $v $c]
+ } else {
+ puts "backedge!"
+ lappend be $v
+ }
+ }
+ $w itemconfigure $c -data [list BackEdges $be]
+ }
+ return $w
+}
+
+# Returns the selected text of a combo box.
+proc GetComboBoxText { cb } {
+ return [lindex [$cb cget -values] [$cb getvalue]]
+}
+
+# Sets a combo box selection from a text value (rather than an index)
+#
+# @param cb Widget path
+# @param v Text value that should be selected.
+# @returns The index of the selection, or -1 if it wasn't there.
+proc SetComboBoxValue { cb v } {
+ set i [lsearch -exact [$cb cget -values] $v]
+ if { $i != -1 } {
+ $cb setvalue @$i ;# who knows why you need the @.
+ }
+ return $i
+}
+
+# Set the text of an entry box
+proc SetEntryText { e s } {
+ set old [$e get]
+ $e delete 0 [expr [string length $old] + 1]
+ $e insert 0 $s
+ return $old
+}
+
+# Get the text from a text widget.
+proc GetTextBoxText { t } {
+ return [$t get 0.0 "end -1 chars"]
+}
+
+# Set the text in a text widget.
+proc SetTextBoxText { e s } {
+ set old [GetTextBoxText $e]
+ $e delete 0.0 "end + 1 chars"
+ $e delete 0.0 ;# Get rid of last extra new-line
+ $e insert 0.0 $s
+ return $old
+}
+
+} ;# namespace eval BwUtil
diff --git a/dmgen-1.0.0/src/config.tcl b/dmgen-1.0.0/src/config.tcl
new file mode 100644
index 0000000..84ffbc9
--- /dev/null
+++ b/dmgen-1.0.0/src/config.tcl
@@ -0,0 +1,235 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# dmgen Config file module.
+
+namespace eval DmGenCfg {
+
+ variable defaults {
+ __section__ 0
+"dmgen configuration file.\n\n\
+Various configuration parameters can be set with this file.\n\
+Parameters are set with this syntax:\n\
+\tSet ParameterName ParameterValue\n\
+Note that is Set with a CAPITAL S\n\
+If ParameterValue has white space, it must be enclosed in quotes.\n\
+Comments are started with the # symbol."
+
+ __section__ 0 "Setup parameters."
+
+ SoarLibraryPath ""
+"Path to Soar library (i.e. /path/to/Soar-x.x/library).\n\
+If this is just an empty string, then the SOAR_LIBRARY environment\n\
+variable is used.\n\
+Example: Set SoarLibraryPath \"c:/soar-8.3/library\""
+
+ __section__ 0 "Datamap generation parameters."
+
+ ProblemSpaceSpec "name"
+"Problem-space path specifier. Space delimited list of attributes\n\
+that gives the path to the problem-space name.\n\
+For TacAirSoar-style systems (^problem-space.name), this would be:\n\
+\tSet ProblemSpaceSpec \"problem-space name\"\n\
+For Visual Soar-style systems (^name), this would be:\n\
+\tSet ProblemSpaceSpec \"name\""
+
+ FillTopPs 1
+"Put anything under a top-state into the top-ps problem space,\n\
+even if it doesn't explicitly reference top-ps problem space name."
+
+ FillAnyPs 1
+"If a production does not test a problem space name, put the\n\
+attributes it tests into the any-ps problem space."
+
+ CopyTopPs 1
+"If FillTopPs is on, copy top-state attributes to top-ps,\n\
+but leave them in the original problem-space as well."
+
+ SaveSourceProds 1
+"Store source production info in the 'prods' attribute of\n\
+each node in the datamap. Since these lists can get really\n\
+long, turning this off can speed things up a bit."
+
+ ExcludedProds {}
+"List of productions that should be excluded from processing.\n\
+Removing large productions that simply load data structures, such as\n\
+maps, can speed up datamap generation process a lot.\n\
+Example: Set ExcludedProds { elaborate*foo propose*bar }"
+
+ __section__ 0 "Output related parameters"
+
+ InputFile source.soar
+"Name of file, in current directory, that is sourced to load all\n\
+productions that should be processed."
+
+ DatamapName Datamap
+"Name given to generated datamap."
+
+ OutputFormat xml
+"Output format to write to. Valid values are:\n\
+\txml - Writes the datamap in XML, suitable for SoarDoc\n\
+\thtml - Writes a simple set of HTML pages\n\
+\tnone - No output\n\
+Example: Set OutputFormat xml"
+
+ OutputDirectory xml
+"Directory to which output is written, relative to current directory\n\
+at time of execution.\n\
+Example: Set OutputDirectory xml"
+
+ LogFileName "dmgenlog.txt"
+"Name of log file, written to the current directory.\n\
+If set to the empty string, then no log is written."
+
+ LogAutoFlush 0
+"If 1, then the logis flushed everytime it is written to.\n\
+This can slow things down a lot, but may be useful for debugging."
+
+ __section__ 0 "HTML output related parameters"
+
+ HtmlHideState 1
+" Don't show the root of the 'tree' since it's redundant (state or operator)"
+
+ HtmlShowComments 1 "Write comments"
+
+ HtmlColorPatched 0
+" If a vertex has been patched by the user, highlight its name."
+
+ HtmlShowSpecial 0
+"Show values of 'special' attributes. Only really useful for debugging."
+
+ HtmlSuppressedAttributes {}
+"List of attribute names that will not be written."
+
+ HtmlMaxValuesPerLine 4
+"Maximum number of attribute values that will be written inline before
+they are moved to the separate values window."
+
+ HtmlMaxSoarListDepth 4
+"Maximum depth to which a detectable soarList is displayed."
+
+ }
+
+ # Table of parameter values, indexed by param name
+ variable params
+ if [array exists params] { unset params }
+
+ ##
+ # Read a config file.
+ proc Read { fileName } {
+ source $fileName
+ }
+
+ ##
+ # Write a config file to the given file.
+ #
+ # @param fileName Name of file to write to, or stdout if it is ""
+ proc Write { { fileName "" } } {
+ if { $fileName != "" } {
+ set fd [open $fileName w]
+ } else {
+ set fd stdout
+ }
+ variable defaults
+ variable params
+ foreach { name value comments } $defaults {
+ if { $name != "__section__" } {
+ puts $fd "##\n# - $name -"
+ set c [join [split $comments "\n"] "\n# "]
+ puts $fd "# $c"
+ set v $params($name)
+ puts $fd "Set $name [escapeValue $v]\n"
+ } else {
+ puts $fd "###############################################################################"
+ set c [join [split $comments "\n"] "\n# "]
+ puts $fd "# $c\n"
+ }
+ }
+ if { $fd != "stdout" } {
+ close $fd
+ }
+ }
+
+ ##
+ # Set the value of a parameter.
+ #
+ # @param param Name of parameter
+ # @param value Value of parameter
+ proc Set { param value } {
+ variable params
+ set params($param) $value
+
+ # Custom param setting code
+ # Todo, make this more data driven!
+ if { $param == "ProblemSpaceSpec" } {
+ Production::ProblemSpaceSpec $value
+ } elseif { $param == "LogFileName" } {
+ LogSetFileName $value
+ } elseif { $param == "LogAutoFlush" } {
+ LogSetAutoFlush $value
+ }
+
+ }
+
+ ##
+ # Get the value of a parameter
+ #
+ # @param Name of parameter
+ proc Get { param } {
+ variable params
+ return $params($param)
+ }
+
+ proc escapeValue { v } {
+ set v [join [split $v "\\"] "\\\\"]
+ set v [join [split $v "\""] "\\\""]
+ if { $v == "" || [regexp "\[ \r\n\t\]" $v] } {
+ set v "\"$v\""
+ }
+ return $v
+ }
+
+ #
+ # Load the default values into the parameter value table.
+ # do this last so we know that Set proc is loaded and callable.
+ foreach { name val comments } $defaults {
+ if { $name != "__section__" } {
+ Set $name $val
+ }
+ }
+
+} ;# namespace eval DmGenCfg
diff --git a/dmgen-1.0.0/src/datamap.tcl b/dmgen-1.0.0/src/datamap.tcl
new file mode 100644
index 0000000..8204f7e
--- /dev/null
+++ b/dmgen-1.0.0/src/datamap.tcl
@@ -0,0 +1,511 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Datamap management code. Manages a set of datamaps created by the user.
+# Also has the Generate function for generating a datamap from a set of
+# productions. Here's the typical usage:
+# ... Load productions ...
+# set dm [Datamap::Create "Name Of Datamap"]
+# Datamap::Generate $dm
+# # Now you can use the various accessor functions to get at the produced
+# # datamap.
+#
+# Requires:
+# util.tcl
+# graph.tcl
+# log.tcl
+# production.tcl
+# partition.tcl
+# merge.tcl
+# config.tcl
+# soarutil.tcl
+
+namespace eval Datamap {
+
+ # Returns a list of valid vertex field names
+ #
+ # name - Name of the "attribute"
+ # value - List of values of the attribute
+ # side - Which side of the production was the attribute on
+ # L = left
+ # R = right
+ # B = both
+ # type - Type of the attribute (int string identifier unknown)
+ # range - currently unused
+ # link - A link to another problemspace or operator. Is a list
+ # where the first element is O or S to indicate type followed
+ # by names of targets...e.g.
+ # { S top-ps any-ps attack-delivery }
+ #
+ # prods - List of production names that contributed to this node.
+ #
+ proc VertexFields {} {
+ return [list name \
+ value \
+ side \
+ type \
+ range \
+ link \
+ special \
+ prods \
+ comment \
+ patched]
+ }
+ # Returns a 'struct' of default vertex field values
+ proc DefVertexFields {} {
+ return [list name unknown \
+ value {} \
+ side B \
+ type identifier \
+ range {} \
+ link {} \
+ special {} \
+ prods {} \
+ comment "" \
+ patched {}]
+ }
+
+ variable datamaps
+ set datamaps(0) 0
+
+ ##
+ # Creates a datamap (problem-spaces + operators) and returns a handle to it
+ #
+ # @param name User-specified name given to the datamap.
+ # @returns A handle to the datamap for use in later calls.
+ proc Create { { name "" }} {
+ variable datamaps
+ set dm [GetTag DM]
+ set datamaps($dm,name) $name
+ return $dm
+ }
+
+ ##
+ # Clear the contents of a datamap. Good for resetting before another call
+ # to Generate.
+ #
+ # @param dm Datmap handle.
+ proc Clear { dm } {
+ variable datamaps
+ # Clean up graphs
+ foreach n [array names datamaps $dm,*,*,graph] {
+ Graph::Destroy $datamaps($n)
+ }
+ # Clean up entries
+ foreach n [array names datamaps $dm,*,*,*] {
+ unset datamaps($n)
+ }
+ }
+ ##
+ # Remove a datamap from memory. The handle will be useless afterward.
+ #
+ # @param dm handle of datamap to destroy.
+ proc Destroy { dm } {
+ variable datamaps
+ Clear $dm
+ unset datamaps($dm,name)
+ }
+
+ ##
+ # Returns the user specified name of a datamap.
+ proc GetName { dm } {
+ variable datamaps
+ if ![info exist datamaps($dm,name)] {
+ return ""
+ }
+ return $datamaps($dm,name)
+ }
+ ##
+ # Create a datamap structure for a problem-space or operator
+ #
+ # @param dm Datamap handle
+ # @param type S (problem space) or O (operator)
+ # @param name Name of ps or op (no whitespace!)
+ # @returns Handle to ps or op
+ proc createPsOrOp { dm type name } {
+ set g [Graph::Create [VertexFields]]
+ set s [$g InsertVertex [DefVertexFields]]
+
+ set names(S) "state"
+ set names(O) "operator"
+
+ $g Set $s name $names($type)
+
+ variable datamaps
+ set datamaps($dm,$type,$name,graph) $g
+ set datamaps($dm,$type,$name,start) $s
+ return "$dm,$type,$name"
+ }
+ ##
+ # Same as createPsOrOp, except that if the requested ps or op already
+ # exists, the existing one is returned rather than creating a new one.
+ #
+ # @param dm Datamap handle
+ # @param type S (problem space) or O (operator)
+ # @param name Name of ps or op (no whitespace!)
+ # @returns Handle to ps or op
+ proc findOrCreatePsOrOp { dm type name } {
+ set h [GetPsOrOp $dm $type $name]
+ if { $h != {} } {
+ return $h
+ }
+ return [createPsOrOp $dm $type $name]
+ }
+ ##
+ # Create a new problem-space and return a handle to it
+ #
+ # @param dm Datamap handle
+ # @param name Name of problem-space (no whitespace!)
+ # @returns a new problem-space handle
+ proc CreateProblemSpace { dm name } {
+ return [createPsOrOp $dm S $name]
+ }
+ proc FindOrCreateProblemSpace { dm name } {
+ return [findOrCreatePsOrOp $dm S $name]
+ }
+ ##
+ # Create a new operator and return a handle to it
+ #
+ # @param dm Datamap handle
+ # @param name Name of operator (no whitespace!)
+ # @returns a new operator handle
+ proc CreateOperator { dm } {
+ return [createPsOrOp $dm O $name]
+ }
+ proc FindOrCreateOperator { dm name } {
+ return [findOrCreatePsOrOp $dm O $name]
+ }
+
+ ##
+ # Remove a problem space or operator from datamap
+ proc removePsOrOp { h } {
+ variable datamaps
+ foreach n [array names datamaps $h,*] {
+ unset datamaps($n)
+ }
+ }
+ proc RemoveProblemSpace { h } { removePsOrOp $h }
+ proc RemoveOperator { h } { removePsOrOp $h }
+
+ ##
+ # Returns a list of ps or op handles in the datamap.
+ #
+ # @param dm Datamap handle
+ # @param type S or O
+ # @returns List of problem-space or operator handles
+ proc getPsOrOps { dm type } {
+ variable datamaps
+ set r {}
+ foreach d [array names datamaps $dm,$type,*,graph] {
+ lappend r [join [lrange [split $d ","] 0 2] ","] ;#Handle
+ }
+ return $r
+ }
+
+ proc GetProblemSpaces { dm } { return [getPsOrOps $dm S] }
+ proc GetOperators { dm } { return [getPsOrOps $dm O] }
+
+ ##
+ # Generate or append to the given datamap using the information in the given
+ # productions. If no productions are given, then all loaded Soar productions
+ # are used.
+ #
+ # @param dm Datamap handle returned by Create
+ # @param prods Optional list of names of productions to process
+ proc Generate { dm { prods {} } } {
+
+ Log ""
+ Log [clock format [clock seconds]]
+ Log "Datamap generation initiated for datamap [GetName $dm]"
+ if { [llength $prods] == 0 } {
+ Log "No productions specified, using all loaded productions."
+ set prods [SoarUtil::GetSoarProductions]
+ }
+ set total 0
+ set passedParse 0
+ set failedParse 0
+ set psOrOpFound 0
+ set noPsOrOpFound 0
+ foreach p $prods {
+ Log "Parsing production: $p"
+ incr total
+ set g [Production::Parse $p]
+ if { $g == {} } {
+ LogError "Error parsing production: $p"
+ incr failedParse
+ } else {
+ incr passedParse
+ set parts [Partition::PartitionProduction $g]
+ if { $parts != {} } {
+ incr psOrOpFound
+ Log "Processing production partitions"
+ ProcessProd $dm $p $g $parts
+ # If the user wants topstate stuff also copied to the ps that
+ # it's used in, we do it one more time with slightly different
+ # options. This is a bit of a hack, but...
+ if { [DmGenCfg::Get CopyTopPs] && [DmGenCfg::Get FillTopPs] } {
+ DmGenCfg::Set FillTopPs 0
+ set parts [Partition::PartitionProduction $g]
+ if { $parts != {} } {
+ Log "Copying top-state to calling problem space"
+ ProcessProd $dm $p $g $parts
+ }
+ DmGenCfg::Set FillTopPs 1
+ }
+ } else {
+ incr noPsOrOpFound
+ Log "No problem spaces or operators identified"
+ }
+ }
+ }
+ Log "Updating attribute types"
+ foreach ps [concat [GetProblemSpaces $dm] [GetOperators $dm]] {
+ updateAttrTypes $ps
+ }
+
+ Log "Pruning extraneous problem-space and operator names"
+ foreach ps [concat [GetProblemSpaces $dm] [GetOperators $dm]] {
+ prunePsAndOpNames $ps
+ }
+
+ # Sort attributes alphabetically by name
+ Log "Sorting attributes"
+ SortAttributes $dm [DefAttrSortPriority]
+
+ Log [clock format [clock seconds]]
+ Log "Datamap Generation complete:"
+ Log " $total productions attempted"
+ Log " $failedParse productions failed to parse"
+ Log " $passedParse productions parsed successfully"
+ Log " $psOrOpFound productions had identifiable problem space or operator"
+ Log " $noPsOrOpFound productions had NO identifiable problem space or operator"
+ LogFlush
+ }
+
+ ##
+ # Get handle to a PS or OP from its type and name
+ # @param dm datamap handle
+ # @param type S or O
+ # @param name Name of ps or op
+ proc GetPsOrOp { dm type name } {
+ variable datamaps
+ set h "$dm,$type,$name"
+ if [info exists datamaps($h,graph)] {
+ return $h
+ }
+ return {}
+ }
+
+ ##
+ # Get handles to particular PS or op of a datamap. Returns {} if it
+ # doesn't exist.
+ proc GetProblemSpace { dm name } { return [GetPsOrOp $dm S $name] }
+ proc GetOperator { dm name } { return [GetPsOrOp $dm O $name] }
+
+ # What datamap does this handle belong to?
+ proc GetDatamap { h } {
+ return [lindex [split $h ","] 0]
+ }
+ # What is the name of the PS or OP that this handle points to.
+ proc GetPsOrOpName { h } {
+ return [lindex [split $h ","] end]
+ }
+ ##
+ # What is the type of this handle
+ # Problem-space -> S
+ # Operator -> O
+ proc GetType { h } {
+ return [lindex [split $h ","] 1]
+ }
+ # Is this handle for a problem space?
+ proc IsProblemSpace { h } {
+ return [expr [string compare [GetType $h] "S"] == 0]
+ }
+ # Is this handle for an operator?
+ proc IsOperator { h } {
+ return [expr [string compare [GetType $h] "O"] == 0]
+ }
+ # Get the graph for this handle
+ proc GetGraph { h } {
+ variable datamaps
+ return $datamaps($h,graph)
+ }
+ # Get the start vertex for the graph of this handle
+ # i.e. The state or operator vertex.
+ proc GetStartVertex { h } {
+ variable datamaps
+ return $datamaps($h,start)
+ }
+
+ ##
+ # Find a vertex given a vertex name path
+ #
+ # @param dmGraph Graph
+ # @param start Vertex to start search from
+ # @param path List of vertex names e.g. { state operator name }
+ # @returns The vertex tag, or Graph::NullVertex if not found
+ proc FindVertexFromPath { dmGraph start path } {
+ set NV [Graph::NullVertex]
+
+ set v $start
+
+ set n [lindex $path 0]
+ if { [string compare [$dmGraph Get $v name] $n] != 0 } {
+ return $NV
+ }
+ if { [llength $path] == 1 } {
+ return $v
+ }
+ set path [lrange $path 1 end]
+
+ foreach s $path {
+ set v [$dmGraph FindVertex name $s [$dmGraph GetOutAdjacencies $v]]
+ if { $v == $NV } {
+ return $NV
+ }
+ }
+ return $v
+ }
+
+ ##
+ # Default priority list for datamap attribute sorting.
+ proc DefAttrSortPriority { } {
+ return [list { \
+ attribute \
+ impasse \
+ operator \
+ problem-space \
+ superstate \
+ top-state \
+ io \
+ name \
+ }]
+ }
+
+ ##
+ # Sort the sub nodes of each node by name.
+ # Names are sorted alphabetically unless the appear in the priority list. If
+ # a name appears in the priority list, it will sort higher than any other
+ # name, unless the other name is also in the priority list and appears
+ # earlier.
+ #
+ # After this is called, a call to GetOutAdjacencies of any graph vertex will
+ # return the adjacencies in the sorted order.
+ #
+ # @param dm Datamap to sort
+ # @param pri Name priority list
+ proc SortAttributes { dm pri } {
+ set stype(float) -real
+ set stype(int) -integer
+ set stype(string) -ascii
+
+ foreach ps [concat [GetProblemSpaces $dm] [GetOperators $dm]] {
+ set g [GetGraph $ps]
+ foreach v [$g GetVertices] {
+ $g SortOutAjacencies $v name "Datamap::byNameSortFunc $pri "
+
+ # Sort the values of the attribute if the type is known.
+ set t [$g Get $v type]
+ if { $t != "unknown" && $t != "identifier" } {
+ set vals [$g Get $v value]
+ $g Set $v value [lsort $stype($t) $vals]
+ }
+ }
+ }
+ }
+
+ ##
+ # Vertex comparison function for sorting nodes by name using a priority list.
+ #
+ # @param priority Priority list
+ # @param g The graph (passed by Graph::SortOutAjacencies)
+ # @param field The field (passed by Graph::SortOutAjacencies)
+ # @param v1 First vertex
+ # @param v2 Second vertex
+ # @returns -1,0, or 1 indicating result of comparing v1 to v2
+ proc byNameSortFunc { priority g field v1 v2 } {
+ set n1 [$g Get $v1 name]
+ set n2 [$g Get $v2 name]
+
+ set i1 [lsearch $priority $n1]
+ set i2 [lsearch $priority $n2]
+
+ if { $i1 >= 0 && $i2 >= 0 } { ;# They're both in the priority list
+ return [expr $i1 - $i2]
+ } elseif { $i1 >= 0 } { ;# v1 is in the priority list
+ return -1
+ } elseif { $i2 >= 0 } { ;# v2 is in the priority list
+ return 1
+ } else { ;# neither is in the priority list, sort alphabetically, case-insensitive
+ return [string compare [string tolower $n1] [string tolower $n2]]
+ }
+ }
+
+ ##
+ # Fix up the type of the attributes after generation
+ proc updateAttrTypes { psOrOp } {
+ set g [GetGraph $psOrOp]
+ foreach v [$g GetVertices] {
+ if { [$g Get $v link] != {} || [llength [$g GetOutAdjacencies $v]] > 0 } {
+ $g Set $v type identifier
+ } else {
+ $g Set $v type [SoarUtil::GuessSoarTypeFromList [$g Get $v value]]
+ }
+ }
+ }
+
+ proc prunePsAndOpNames { psOrOp } {
+ if [IsProblemSpace $psOrOp] {
+ set spec "ProblemSpaceSpec"
+ } else {
+ set spec "OperatorSpec"
+ }
+ set g [GetGraph $psOrOp]
+ set name [GetPsOrOpName $psOrOp]
+
+ foreach v [$g GetVertices] {
+ if { [$g Get $v special] == $spec } {
+ set vals [$g Get $v value]
+ if { [llength $vals] > 0 && \
+ [lsearch -exact $vals $name] != -1 } {
+ $g Set $v value $name
+ }
+ }
+ }
+ }
+} ;# namespace Datamap
+
diff --git a/dmgen-1.0.0/src/dijkstra.tcl b/dmgen-1.0.0/src/dijkstra.tcl
new file mode 100644
index 0000000..517416f
--- /dev/null
+++ b/dmgen-1.0.0/src/dijkstra.tcl
@@ -0,0 +1,151 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Implementation of Dijkstra's single-source shortest paths algorithm.
+#
+# requires:
+# graph.tcl
+
+namespace eval Dijkstra {
+
+ variable d
+ set d([Graph::NullVertex]) {}
+ variable pi
+ set pi([Graph::NullVertex]) {}
+
+ proc Inf { } { return 99999999 }
+
+ ##
+ # Algorithm initialization function. Called internally
+ proc initSingleSource { g s } {
+ variable d
+ variable pi
+ foreach v [$g GetVertices] {
+ set d($v) [Inf]
+ set pi($v) [Graph::NullVertex]
+ }
+ set d($s) 0
+ }
+
+ ##
+ # Vertex 'relaxation' used internally.
+ proc relax { u v w } {
+ variable d
+ variable pi
+ if { $d($v) > $d($u) } {
+ set d($v) [expr $d($u) + [$w $u $v]]
+ set pi($v) $u
+ }
+ }
+
+ ##
+ # Calculate single source shortest paths on a graph using Dijkstra's
+ # algorithm.
+ # Returns an adjacency array.
+ #
+ # @param g Graph to process
+ # @param w Edge weight function. Takes two vertices and returns the weight
+ # of the edge between them. See UnitWeight below.
+ # @param s Source vertex
+ # @returns An adjacency array. See test code below.
+ proc ShortestPaths { g w s } {
+ variable d
+ variable pi
+ unset d
+ unset pi
+
+ initSingleSource $g $s
+ set s {}
+ set q [$g GetVertices]
+ while { [llength $q] > 0 } {
+ set u [getQMin q]
+ set s [lunion $s $u]
+ foreach v [$g GetOutAdjacencies $u] {
+ relax $u $v $w
+ }
+ }
+ return [array get pi]
+ }
+
+ proc getQMin { qref } {
+ upvar 1 $qref q
+ variable d
+ variable pi
+
+ set mv [lindex $q 0]
+ if { [llength $q] == 1 } {
+ set q {}
+ return $mv
+ }
+ foreach v [lrange $q 1 end] {
+ if { $d($v) < $d($mv) } {
+ set mv $v
+ }
+ }
+ set q [ldelete $q $mv]
+ return $mv
+ }
+
+ # A weight function that returns a unit weight for all edges.
+ proc UnitWeight { u v } { return 1 }
+
+ proc test { } { ;# Some test code...
+ set g [Graph::Create { name }] ;# Create a graph where each vertex has a 'name' field
+ set n1 [$g InsertVertex { name 1 }]
+ set n2 [$g InsertVertex { name 2 }]
+ set n3 [$g InsertVertex { name 3 }]
+ set n4 [$g InsertVertex { name 4 }]
+ set n5 [$g InsertVertex { name 5 }]
+
+ $g AddEdge $n1 $n2
+ $g AddEdge $n2 $n3
+ $g AddEdge $n2 $n4
+ $g AddEdge $n4 $n5
+ $g AddEdge $n5 $n3
+
+ array set pi [ShortestPaths $g UnitWeight $n1]
+ set v $pi($n5)
+ while { $v != [Graph::NullVertex] } {
+ puts "[$g Get $v name] -> "
+ set v $pi($v)
+ }
+ }
+}
+
+IfStandAlone { ;# Some test code
+ Dijkstra::test
+}
diff --git a/dmgen-1.0.0/src/dmgen.tcl b/dmgen-1.0.0/src/dmgen.tcl
new file mode 100644
index 0000000..8ad7206
--- /dev/null
+++ b/dmgen-1.0.0/src/dmgen.tcl
@@ -0,0 +1,343 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Main dmgen program
+
+set dmGenVersion "1.0"
+
+##
+# Generate a datamap and bring up the datamap window
+# This function is for use when dmgen has been manually loaded
+# into a Tcl interpretter.
+#
+# @param name Name of the datamap
+# @param prods List of productions to process or {} for all loaded.
+# @param compiled Strictly for debugging. Ignore.
+# @returns The generated datamap
+proc GenerateDatamap { { name "" } { prods {} } { compiled 1 } } {
+ global tk_version DmGenCompiled
+
+ set DmGenCompiled $compiled
+
+ set dm [Datamap::Create $name]
+ Datamap::Generate $dm $prods
+ if [info exists tk_version] {
+ DmWin::Create $dm
+ }
+ return $dm
+}
+
+
+###
+## Everything from here down is for running from the command line.
+proc dmGenUsage {} {
+ puts stderr "Usage: tclsh path/to/dmgen.tcl \[options\]"
+ puts stderr " -g : Prints a default config file to stdout."
+ puts stderr " -f configFile : Specify a config file. Defaults to \"dmgenfile\"."
+ puts stderr " -h : Print this message and exit."
+ puts stderr " -C param value : Set configuration parameter, overriding config file."
+ puts stderr " -v : Print dmgen version."
+}
+
+proc dmGenPrintVersion { } {
+ global dmGenVersion
+ puts "Version $dmGenVersion"
+}
+
+if [info exists dmGenArgs] {
+ unset dmGenArgs
+}
+
+set dmGenArgs(GenerateConfig) 0
+set dmGenArgs(ConfigParams) {}
+set dmGenArgs(Args) {}
+
+proc dmGenParseArgs { } {
+ global dmGenArgs argc argv
+
+ for { set i 0 } { $i < $argc } { incr i } {
+ set arg [lindex $argv $i]
+ if { [string index $arg 0] == "-" } {
+ set opt [string range $arg 1 end]
+ if { $opt == "C" } {
+ if { [expr $argc - $i] < 3 } {
+ puts stderr "Too few arguments to option -C"
+ return 0
+ }
+ set param [lindex $argv [expr $i + 1]]
+ set val [lindex $argv [expr $i + 2]]
+ lappend dmGenArgs(ConfigParams) $param
+ lappend dmGenArgs(ConfigParams) $val
+
+ # Skip the args
+ incr i 2
+ } elseif { $opt == "f" } {
+ if { [expr $argc - $i] < 2 } {
+ puts stderr "Too few arguments to option -f"
+ return 0
+ }
+ set cfgFile [lindex $argv [expr $i + 1]]
+ set dmGenArgs(ConfigFile) $cfgFile
+
+ # Skip the arg
+ incr i
+ } elseif { $opt == "g" } {
+ set dmGenArgs(GenerateConfig) 1
+ } elseif { $opt == "h" } {
+ return 0
+ } elseif { $opt == "v" } {
+ dmGenPrintVersion
+ exit 0
+ } else {
+ puts stderr "Unknown option $opt"
+ return 0
+ }
+ } else {
+ lappend dmGenArgs(Args) $arg
+ }
+ }
+ return 1
+}
+
+proc dmGenGetProdList { } {
+ set excluded [DmGenCfg::Get ExcludedProds]
+
+ if { $excluded == {} } {
+ return {}
+ }
+ set loaded [SoarUtil::GetSoarProductions]
+ set prods {}
+ foreach p $loaded {
+ if { [lsearch $excluded $p] == -1 } {
+ lappend prods $p
+ }
+ }
+ return $prods
+}
+
+proc dmGenMain { } {
+ global dmGenArgs DmGenCompiled env tk_version auto_path errorInfo
+
+ puts stderr "dmgen - A Soar static datamap generation tool by Soar Technology, Inc."
+
+ # set up auto_path for dmgen
+ # the foreach is just a cheap way of expanding the tuple
+ # without having to use lindex and all that.
+ foreach { dirName scriptName } [dmGenGetPathToScript] {
+ if { $scriptName != "dmgen.tcl" } {
+ puts stderr "dmGenMain must be called from top-level"
+ exit 1
+ }
+ if ![file exists $dirName] {
+ puts stderr "Could not determine location of dmgen.tcl"
+ exit 1
+ }
+ # Don't really need this any more, see related comment in tclIndex.
+ #set DmGenCompiled [file exists [file join $dirName "compiled.txt"]]
+
+ lappend auto_path $dirName
+ break
+ }
+
+ # parse args
+ if ![dmGenParseArgs] {
+ dmGenUsage
+ exit 1
+ }
+
+ if { $dmGenArgs(GenerateConfig) } {
+ # Load command-line config overrides, if any
+ foreach { param value } $dmGenArgs(ConfigParams) {
+ DmGenCfg::Set $param $value
+ }
+ DmGenCfg::Write
+ exit 0
+ }
+
+ # Load config file, if any
+ if [info exists dmGenArgs(ConfigFile)] {
+ set configFile $dmGenArgs(ConfigFile)
+ } elseif [file exists dmgenfile] {
+ set configFile dmgenfile
+ }
+ if [info exists configFile] {
+ if { [catch { DmGenCfg::Read $configFile } ] } {
+ puts stderr "Error while loading config file \"$configFile\":\n$errorInfo"
+ exit 1
+ }
+ }
+
+ # Load command-line config overrides, if any
+ foreach { param value } $dmGenArgs(ConfigParams) {
+ DmGenCfg::Set $param $value
+ }
+
+ # set up auto_path for Soar
+ set soarLibPath [DmGenCfg::Get SoarLibraryPath]
+ if { $soarLibPath != "" } {
+ # user is overriding SOAR_LIBRARY env. var.
+ set env(SOAR_LIBRARY) $soarLibPath
+ } elseif [info exists env(SOAR_LIBRARY)] {
+ set soarLibPath $env(SOAR_LIBRARY)
+ } else {
+ LogError "No Soar library path was specified."
+ exit 1
+ }
+ if ![file exists $soarLibPath] {
+ LogError "Specified Soar library path \"$soarLibPath\" does not exist."
+ exit 1
+ }
+ lappend auto_path $soarLibPath
+ package require Soar
+
+ # load user-specified source.soar
+ set inputFile [DmGenCfg::Get InputFile]
+ if ![file exists $inputFile] {
+ LogError "Could not find input file: $inputFile"
+ exit 1
+ }
+
+ puts "Sourcing input file"
+ if { [catch { source $inputFile }] } {
+ LogError "Error while sourcing input file \"$inputFile\":\n$errorInfo"
+ exit 1
+ }
+ puts "Done Sourcing input file"
+
+ # run dmgen
+ set dm [Datamap::Create [DmGenCfg::Get DatamapName]]
+ Datamap::Generate $dm [dmGenGetProdList]
+ if [info exists tk_version] {
+ DmWin::Create $dm
+ }
+ # write out any desired output...
+ set outFmt [DmGenCfg::Get OutputFormat]
+ set outDir [DmGenCfg::Get OutputDirectory]
+ if { $outFmt == "xml" } {
+ file mkdir $outDir
+ DmGenXmlOut::WriteXmlDatamap $outDir $dm
+ } elseif { $outFmt == "html" } {
+ file mkdir $outDir
+ DmGenHtmlOut::WriteHtmlDatamap $outDir $dm
+ } elseif { $outFmt == "none" } {
+ # That was easy.
+ } else {
+ LogError "Unknown output format: $outFmt"
+ exit 1
+ }
+}
+
+##
+# Same as the proc in util.tcl, but we need it here before
+# util.tcl may be loaded :(
+proc dmGenJoinPathList { pathList } {
+ set r ""
+ foreach p $pathList {
+ set r [file join $r $p]
+ }
+ return $r
+}
+
+##
+# Same as the proc in util.tcl, but we need it here before
+# util.tcl may be loaded :(
+proc dmGenGetPathToScript { } {
+ set relPath [info script]
+ set scriptName [file tail $relPath]
+ set dirName [file dirname $relPath]
+
+ set pathType [file pathtype $dirName]
+ if { $pathType == "absolute" } {
+ return [list $dirName $scriptName]
+ } elseif { $pathType == "relative" } {
+ set cur [file split [pwd]]
+ set parts [file split $dirName]
+ set end [llength $cur]
+ for { set i 0 } { $i < [llength $parts] } { incr i } {
+ set p [lindex $parts $i]
+ if { $p == ".." } {
+ incr end -1
+ } elseif { $p != "." } {
+ break
+ }
+ }
+ set full [concat [lrange $cur 0 [expr $end - 1]] \
+ [lrange $parts $i end]]
+ return [list [dmGenJoinPathList $full] $scriptName]
+ } else { ;# volumerelative
+ return [list $dirName $scriptName]
+ }
+}
+if $tcl_interactive {
+
+} else {
+ dmGenMain
+}
+
+##
+# Don't really need this stuff anymore. If we do need it at some point,
+# it goes at the top of the file.
+#
+#global DmGenAutoLoaded
+## Only source dependencies if we're not auto loading...
+#if { ($tcl_interactive && ![info exists DmGenAutoLoaded]) } {
+# puts "Not auto-loaded, sourcing files"
+# source "util.tcl"
+# source "log.tcl"
+# source "graph.tcl"
+# source "dijkstra.tcl"
+#
+# source "soarutil.tcl"
+# source "lexer.tcl"
+# source "parser.tcl"
+# source "production.tcl"
+# source "partition.tcl"
+# source "merge.tcl"
+# source "datamap.tcl"
+#
+# source "htmlout.tcl"
+# source "xmlout.tcl"
+#
+# source "dmpatch.tcl"
+# source "config.tcl"
+#
+# if [info exists tk_version] {
+# source "bwutil.tcl"
+# source "dmwin.tcl"
+# source "patchwin.tcl"
+# }
+#}
diff --git a/dmgen-1.0.0/src/dmpatch.tcl b/dmgen-1.0.0/src/dmpatch.tcl
new file mode 100644
index 0000000..5a66810
--- /dev/null
+++ b/dmgen-1.0.0/src/dmpatch.tcl
@@ -0,0 +1,161 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Code to support "patching" of generated datamaps.
+# A patch file is a tcl file with a series of patch commands that modify
+# datamap attributes and mark them as patched. The code in this file
+# implements support for reading and writing patch files.
+#
+# The following types of patches are currently supported:
+# Modifying values of datamap vertex attributes.
+# 'attributes' include name, type, value, link, prods, etc.
+#
+# The following types of patches would be nice, but are tougher:
+# Add new vertex to datamap (pretty easy)
+# Remove vertex from datamap (harder)
+# Add new edge to datamap (not that hard)
+#
+# Requires:
+# dijkstra.tcl
+# datamap.tcl
+# graph.tcl
+
+namespace eval DmPatch {
+
+ ##
+ # Set the value of a vertex field and update the vertex patch
+ # set appropriately.
+ #
+ # @param h PS or OP handle
+ # @param path .-seperated path from start vertex to vertex to modify
+ # e.g. state.operator.name
+ # @param field Name of field to patch
+ # @param value New field value
+ # @return 1 on success, 0 on failure
+ proc PatchVertex { h path field value } {
+ set g [Datamap::GetGraph $h]
+ set s [Datamap::GetStartVertex $h]
+ set path [split $path "."]
+ set v [Datamap::FindVertexFromPath $g $s $path]
+ if { $v == [Graph::NullVertex] } {
+ LogError "Vertex $path could not be found in datamap graph!"
+ return 0
+ }
+
+ PatchVertexFast $g $v $field $value
+ return 1
+ }
+
+ proc PatchVertexFast { g v field value } {
+ $g Set $v $field $value
+
+ set patched [$g Get $v patched]
+ set patched [lunion $patched $field]
+ $g Set $v patched $patched
+ }
+
+ proc RemoveVertex { dmStruct v } {
+
+ }
+
+ ##
+ # Write a patch file for a datamap to a file.
+ #
+ # @param dm Datamap to write patch file for
+ # @param fn Name of file.
+ # @returns 1 on success, 0 on failure.
+ proc SavePatches { dm fn } {
+ set fd [open $fn w]
+ set pss [lsort [Datamap::GetProblemSpaces $dm]]
+ set ops [lsort [Datamap::GetOperators $dm]]
+ foreach h [concat $pss $ops] {
+ writePatch $fd $h
+ }
+ close $fd
+ }
+ ##
+ # Write patches for a particular operator or problem space
+ #
+ # @param fd File descriptor to write to.
+ # @param h Handle to PS or OP.
+ proc writePatch { fd h } {
+ set g [Datamap::GetGraph $h]
+ set start [Datamap::GetStartVertex $h]
+ set type [Datamap::GetType $h]
+ set name [Datamap::GetPsOrOpName $h]
+ array set pi [Dijkstra::ShortestPaths $g Dijkstra::UnitWeight $start]
+ foreach v [$g GetVertices] {
+ set patches [$g Get $v patched]
+ set path [join [GetVertexPath $g $start $v pi] "." ]
+ foreach field $patches {
+ set value [$g Get $v $field]
+ puts $fd "DmPatch::PatchVertex \"\$PDM,$type,$name\" $path $field \{$value\}"
+ }
+ }
+ }
+
+ ##
+ # Load a patch file and apply it to a datamap.
+ #
+ # @param dm Datamap that patches will be applied to.
+ # @param fn Name of file.
+ proc ApplyPatchFile { dm fn } {
+ set PDM $dm ;# The patchfile is expecting this variable..
+ source $fn
+ }
+
+ ##
+ # Get the name path to a vertex.
+ #
+ # @param g Graph
+ # @param s Start vertex of path
+ # @param v Vertex we want the path to
+ # @param rpi Name of an array initialized from running Dijkstra
+ # ShortestPaths on $g $s.
+ # @returns A list of vertex names, e.g. { state operator name }
+ proc GetVertexPath { g s v rpi } {
+ upvar 1 $rpi pi
+
+ set path [$g Get $v name]
+ set v $pi($v)
+ while { $v != [Graph::NullVertex] } {
+ set path [concat [$g Get $v name] $path]
+ set v $pi($v)
+ }
+ return $path
+ }
+} ;# namespace DmPatch
diff --git a/dmgen-1.0.0/src/dmwin.tcl b/dmgen-1.0.0/src/dmwin.tcl
new file mode 100644
index 0000000..80b53b5
--- /dev/null
+++ b/dmgen-1.0.0/src/dmwin.tcl
@@ -0,0 +1,212 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Main datamap window.
+# Just has menus for saving patches and HTML export and for displaying
+# problem-space and operators
+#
+# Requires:
+# bwutil.tcl
+# htmlout.tcl
+# datamap.tcl
+# patchwin.tcl
+# dmpatch.tcl
+
+package require BWidget
+
+namespace eval DmWin {
+ # Get the name of the window for the given datamap
+ proc Get { dm } { return .$dm }
+
+ # Create a window for the given datamap unless one already exists, in
+ # which case the existing window is simply raised.
+ proc Create { dm } {
+ # If there's already a window for this handle, raise it and return
+ set w .$dm
+ if [winfo exists $w] {
+ raise $w
+ return $w
+ }
+ set w [toplevel $w]
+
+ bind $w [list DmWin::onDestroy {%W} $w $dm]
+
+ wm title $w "Datamap: [Datamap::GetName $dm]"
+
+ # Create a menu bar
+ set mb [menu $w.mb]
+ $w config -menu $mb
+ foreach m { File ProblemSpaces Operators } {
+ set mnu$m [menu $mb.mnu$m]
+ $mb add cascade -label $m -menu $mb.mnu$m
+ }
+
+ $mnuFile add command -label "Apply patch file" \
+ -command "DmWin::onApplyPatch $w $dm"
+ $mnuFile add command -label "Save patch file" \
+ -command "DmWin::onSavePatch $w $dm"
+ $mnuFile add command -label "Export to HTML" \
+ -command "DmWin::onExportToHtml $w $dm"
+ $mnuFile add command -label "Export to XML" \
+ -command "DmWin::onExportToXml $w $dm"
+
+ $mnuProblemSpaces config -postcommand "DmWin::psMenuPost $w $dm"
+ $mnuOperators config -postcommand "DmWin::opMenuPost $w $dm"
+
+ set f [LabelFrame $w.htmlFrame \
+ -text "HTML Export Options" \
+ -side top -relief ridge]
+ foreach { v l } { HtmlHideState "Hide State/Operator" \
+ HtmlShowComments "Show Comments" \
+ HtmlColorPatched "Highlight Patched Attributes" \
+ HtmlShowSpecial "Show special tags" } {
+
+ set cb [checkbutton $f.[string tolower $v] \
+ -text $l \
+ -variable DmGenCfg::params($v) \
+ -anchor w]
+ pack $cb -side top
+ }
+ pack [label $f.suppressedAttrLbl -text "Suppressed Attributes:"] -side top
+ pack [entry $f.suppressedAttr \
+ -textvariable DmGenCfg::params(SuppressedAttributes)] -side top
+
+ pack $f -side left
+
+ return $w
+ }
+ proc onDestroy { widget w dm } {
+ if { [string compare $widget $w] != 0 } { return }
+
+ # Clean up all problem-space and operator windows we've
+ # spawned.
+ set all [concat [Datamap::GetProblemSpaces $dm] \
+ [Datamap::GetOperators $dm]]
+ foreach h $all {
+ if [winfo exists [PatchWin::Get $h]] {
+ destroy [PatchWin::Get $h]
+ }
+ }
+ }
+ proc onApplyPatch { w dm } {
+ set tl {
+ { "Datamap Patch File" { ".dmp" } }
+ { "All Files" {*} }
+ }
+ set f [tk_getOpenFile -title "Apply Datamap Patch File..." \
+ -parent $w \
+ -filetypes $tl]
+ if { $f != "" } { ;# user pressed open
+ DmPatch::ApplyPatchFile $dm $f
+ }
+
+ }
+ proc onSavePatch { w dm } {
+ set tl {
+ { "Datamap Patch File" { ".dmp" } }
+ { "All Files" {*} }
+ }
+ set f [tk_getSaveFile -title "Apply Datamap Patch File..." \
+ -parent $w \
+ -initialfile "[Datamap::GetName $dm].dmp" \
+ -filetypes $tl]
+ if { $f != "" } { ;# user pressed open
+ DmPatch::SavePatches $dm $f
+ }
+ }
+
+ proc onExportToHtml { w dm } {
+ set tl {
+ { "HTML Files" { ".html" } }
+ { "All Files" {*} }
+ }
+ # tk_chooseDirectory isn't available until Tk8.3 :(
+ set msg "You will now be asked to choose a directory for HTML export.
+ Tk8.0 doesn't have a choose directory command, so please choose a file and
+ the HTML export will output to a directory called html located in the same
+ directory as the file you choose."
+ tk_messageBox -message $msg
+ set f [tk_getSaveFile -title "Export Datamap To HTML..." \
+ -parent $w \
+ -initialfile "[Datamap::GetName $dm].html" \
+ -filetypes $tl]
+ if { $f != "" } { ;# user pressed open
+ set dirName [file join [file dirname $f] html]
+ file mkdir $dirName
+ DmGenHtmlOut::WriteHtmlDatamap $dirName $dm
+ }
+ }
+
+ proc onExportToXml { w dm } {
+ set tl {
+ { "XML Files" { ".xml" } }
+ { "All Files" {*} }
+ }
+ # tk_chooseDirectory isn't available until Tk8.3 :(
+ set msg "You will now be asked to choose a directory for XML export.
+ Tk8.0 doesn't have a choose directory command, so please choose a file and
+ the XML export will output to a directory called XML located in the same
+ directory as the file you choose."
+ tk_messageBox -message $msg
+ set f [tk_getSaveFile -title "Export Datamap To XML..." \
+ -parent $w \
+ -initialfile "[Datamap::GetName $dm].xml" \
+ -filetypes $tl]
+ if { $f != "" } { ;# user pressed open
+ set dirName [file join [file dirname $f] xml]
+ file mkdir $dirName
+ DmGenXmlOut::WriteXmlDatamap $dirName $dm
+ }
+ }
+
+ proc psMenuPost { w dm } {
+ set mnu $w.mb.mnuProblemSpaces
+ $mnu delete 0 end
+ foreach ps [lsort [Datamap::GetProblemSpaces $dm]] {
+ set n [Datamap::GetPsOrOpName $ps]
+ $mnu add command -label $n -command "PatchWin::Create $ps"
+ }
+ }
+ proc opMenuPost { w dm } {
+ set mnu $w.mb.mnuOperators
+ $mnu delete 0 end
+ foreach op [lsort [Datamap::GetOperators $dm]] {
+ set n [Datamap::GetPsOrOpName $op]
+ $mnu add command -label $n -command "PatchWin::Create $op"
+ }
+ }
+}
diff --git a/dmgen-1.0.0/src/graph.tcl b/dmgen-1.0.0/src/graph.tcl
new file mode 100644
index 0000000..a37373e
--- /dev/null
+++ b/dmgen-1.0.0/src/graph.tcl
@@ -0,0 +1,476 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# A graph data structure
+#
+# The graph is stored as a table (array)
+# Each vertex is given a unique tag.
+#
+# graph(__vertices__) = List of tags of all vertices in graph.
+# graph($tag) = list of tags of adjacencent vertices, if any
+# graph(__fields__) = List of user-specified fields for each vertex
+# These fields are automatically unset when a vertex is
+# deleted.
+# $graph($tag,field) = Value of vertex field if set
+#
+# Sample: See test-code at end of file
+#
+# Requires:
+# util.tcl
+
+namespace eval Graph {
+
+ ##
+ # Constant tag used to indicate an invalid vertex tag.
+ proc NullVertex {} { return -1 }
+
+##
+# Create a new graph
+#
+# To create a graph:
+# set T [Graph::Create [list name type value]]
+#
+# @param List of user field names used for each vertex
+# @returns Name of graph access proc
+proc Create { fields } {
+ set graphTag [GetTag Graph]
+ variable $graphTag
+ upvar 0 $graphTag graph
+
+ # Initialize the basic graph structure
+ set graph(__tag__) $graphTag
+ set graph(__fields__) $fields
+ set graph(__vertices__) {}
+
+ # Add a global procedure for accessing this graph
+ # Using eval forces the variable argument list to be expanded so we can pass
+ # it to the proc.
+ proc ::$graphTag { cmd args } "return \[eval Graph::\$cmd $graphTag \$args\]"
+
+ return $graphTag
+}
+
+##
+# Destroy a graph returned by Create.
+#
+# Graph::Destroy $T
+proc Destroy { graph } {
+ unset Graph::$graph ;# Remove the table
+ rename $graph {} ;# Remove the access procedure
+}
+
+
+##
+# Make a copy of the graph and return it.
+#
+# @param graphName Tree to copy
+# @param fields list of Fields of new graph
+# @param copycmd Command to execute to copy fields
+proc Copy { graphName { fields "" } { copycmd Graph::BasicVertexCopy } } {
+ if { $fields == "" } {
+ set fields [GetFields $graphName]
+ }
+ set new [Create $fields]
+
+ upvar 0 $graphName graph
+ upvar 0 Graph::$new newGraph
+
+ set graphTag $graph(__tag__)
+ foreach n $graph(__vertices__) {
+ lappend newGraph(__vertices__) $n
+ set newGraph($n) $graph($n) ;# Copy adjacencies
+ $copycmd $new $n $graphTag $n
+ }
+ return $new
+}
+
+##
+# Insert a new vertex in the graph.
+#
+# @param graphName Name of graph
+# #param fields List of field/value pairs to initialize the vertex (optional)
+# @returns Tag of new vertex
+proc InsertVertex { graphName { fields { } } } {
+ upvar 0 Graph::$graphName graph
+
+ set tag [GetTag GraphVertices 1] ;# Get new tag for vertex
+ set graph($tag) { }
+ lappend graph(__vertices__) $tag ;# Add to vertex list
+
+ SetAll $graphName $tag $fields ;# Set fields of vertex
+
+ return $tag
+}
+proc AddEdge { graphName start end } {
+ upvar 0 Graph::$graphName graph
+
+ set i [lsearch -exact $graph($start) $end]
+ if { $i < 0 } { ;# If the edge doesn't already exist
+ lappend graph($start) $end
+ }
+}
+proc RemoveEdge { graphName start end } {
+ upvar 0 Graph::$graphName graph
+
+ set graph($start) [ldelete $graph($start) $end]
+}
+# Set a single field of a vertex
+proc Set { graphName vertex name value } {
+ upvar 0 Graph::$graphName graph
+ set graph($vertex,$name) $value
+}
+proc SetL { graphName vertex values } {
+ upvar 0 Graph::$graphName graph
+ foreach { n v } $values {
+ set graph($vertex,$n) $v
+ }
+}
+proc SetAll { graphName vertex values } {
+ upvar 0 Graph::$graphName graph
+
+ array set avals $values
+ foreach { f } $graph(__fields__) {
+ if [info exists avals($f)] { ;# Only copy valid fields
+ set graph($vertex,$f) $avals($f)
+ }
+ }
+}
+proc Get { graphName vertex { name "" } } {
+ upvar 0 Graph::$graphName graph
+ if { $name != "" } {
+ return $graph($vertex,$name)
+ }
+
+ set r {}
+ foreach f $graph(__fields__) {
+ if [info exists graph($vertex,$f)] {
+ lappend r $f $graph($vertex,$f)
+ } else {
+ lappend r $f {}
+ }
+ }
+ return $r
+}
+
+##
+# Delete a vertex from the graph.
+# Removes vertex and all adjacencies
+#
+# @param graphName Name of graph
+# @param tag Tag of vertex to remove
+proc DeleteVertex { graphName tag } {
+ upvar 0 Graph::$graphName graph
+
+ if ![info exists graph($tag)] {
+ return
+ }
+
+ # Remove incoming adjacencies
+ foreach n [GetInAdjacencies $graphName $tag] {
+ RemoveEdge $graphName $n $tag
+ }
+ unset graph($tag) ;# remove outgoing adjacencies
+
+ # Eliminate the vertex's user fields if set
+ foreach f $graph(__fields__) {
+ if [info exists graph($tag,$f)] {
+ unset graph($tag,$f)
+ }
+ }
+ # Remove vertex from vertex list
+ set graph(__vertices__) [ldelete $graph(__vertices__) $tag]
+
+}
+
+
+# Returns list of user fields in graph
+proc GetFields { graphName } {
+ upvar 0 Graph::$graphName graph
+ return $graph(__fields__)
+}
+# Returns list of vertex in graph
+proc GetVertices { graphName } {
+ upvar 0 Graph::$graphName graph
+ return $graph(__vertices__)
+}
+
+proc EdgeExists { graphName start end } {
+ upvar 0 Graph::$graphName graph
+
+ return [expr \
+ [lsearch -exact \
+ [GetOutAdjacencies $graphName $start] $end] \
+ >= 0]
+}
+# Returns adjacency list of vertex
+proc GetOutAdjacencies { graphName tag } {
+ upvar 0 Graph::$graphName graph
+
+ return $graph($tag)
+}
+proc GetInAdjacencies { graphName tag } {
+ upvar 0 Graph::$graphName graph
+ set r { }
+ foreach n $graph(__vertices__) {
+ if { [EdgeExists $graphName $n $tag] } {
+ lappend r $n
+ }
+ }
+ return $r
+}
+
+##
+# Visit vertices in order that they were inserted
+#
+# @param graphName Name of graph
+# @param cmd Command to invoke at each vertex. graph and vertex tag will
+# be appended to command each invokation
+# @param rval If true, a list of return values is constructed
+# @returns List of return values of command invokations
+proc Map { graphName cmd { rval 1 } } {
+ if [IsEmpty $graphName] {
+ return
+ }
+ upvar 0 Graph::$graphName graph
+ if { $rval } {
+ set o {}
+ foreach { t } $graph(__vertices__) {
+ lappend o [$cmd $graph(__tag__) $t]
+ }
+ return $o
+ }
+
+ foreach { t } $graph(__vertices__) {
+ $cmd $graph(__tag__) $t
+ }
+}
+
+##
+# Visit vertices from a start vertex in a depth first manner.
+#
+# @param graphName Name of graph
+# @param cmd Command to invoke at each vertex. graphName and vertex tag
+# will be append to command each invokation
+# @param tag Start vertex. This vertex is not visited so you'll
+# have to expclicity visit it yourself prior to invkoing this
+# proc.
+proc MapDepthFirst { graphName cmd { tag TOP } { lvl -1 } } {
+ upvar 0 Graph::$graphName graph
+ incr lvl
+ foreach n $graph(__vertices__) {
+ set visited($n) 0
+ }
+ set visited($tag) 1
+ foreach { t } $graph($tag) {
+ $cmd $graph(__tag__) $t $lvl
+ MapDepthFirst $graphName $cmd $t $lvl
+ }
+}
+
+##
+# Visit vertices from a start vertex in a breadth first manner.
+#
+# @param graphName Name of graph
+# @param tag Start vertex. This vertex is not visited so you'll
+# have to expclicity visit it yourself prior to invkoing this
+# proc.
+# @param cmd Command to invoke at each vertex. graphName and vertex tag
+# will be append to command each invokation
+proc MapBreadthFirst { graphName tag cmd} {
+ upvar 0 Graph::$graphName graph
+
+ foreach n $graph(__vertices__) {
+ set visited($n) 0
+ }
+ set visited($tag) 1
+
+ set L [list $tag]
+
+ while { [llength $L] > 0 } {
+ set v [lindex $L 0] ;# Get head of queue
+ set L [lrange $L 1 end] ;# Pop head of queue
+ $cmd $graph(__tag__) $v
+ foreach n $graph($v) {
+ if { !$visited($n) } { ;# If vertex hasn't been visited
+ set visited($n) 1
+ lappend L $n ;# add to end of queue
+ }
+ }
+ }
+}
+
+##
+# Visit outgoing adjacenies of a vertex (one level only)
+#
+# @param graphName Name of graph
+# @param cmd Command to invoke at each vertex. graphName and vertex tag will
+# be append to command each invokation
+# @param tag Vertex whose children should be visited.
+proc MapOutAdjacencies { graphName cmd tag } {
+ upvar 0 Graph::$graphName graph
+ foreach { t } $graph($tag) {
+ $cmd $graph(__tag__) $t $lvl
+ }
+}
+##
+# Visit incoming adjacenies of a vertex (one level only)
+#
+# @param graphName Name of graph
+# @param cmd Command to invoke at each vertex. graphName and vertex tag will
+# be append to command each invokation
+# @param tag Vertex whose children should be visited.
+proc MapInAdjacencies { graphName cmd tag } {
+ upvar 0 Graph::$graphName graph
+ set verts [GetInAdjacencies $graphName $tag]
+ foreach { t } $verts {
+ $cmd $graph(__tag__) $t $lvl
+ }
+}
+
+##
+# Return whether or not the graph is empty
+#
+proc IsEmpty { graphName } {
+ return [expr [Size $graphName] == 0]
+}
+##
+# Returns the number of vertices in the graph
+#
+proc Size { graphName } {
+ upvar 0 Graph::$graphName graph
+ return [llength $graph(__vertices__)]
+}
+
+##
+# Find a vertex with the specified value for the specified field.
+#
+# @param graphName Name of graph
+# @param field Name of field to check
+# @param value Value to to compare
+# @param verts Set of verts to search, defaults to all verts in graph
+# @returns Vertex tag or {} if none found
+proc FindVertex { graphName field value { verts {} } } {
+ if { $verts == {} } {
+ set verts [$graphName GetVertices]
+ }
+ foreach v $verts {
+ if { $value == [$graphName Get $v $field] } {
+ return $v
+ }
+ }
+ return [NullVertex]
+}
+
+##
+# Field-by-field copy function that is the default field copy function for the
+# Copy method.
+proc BasicVertexCopy { destTree destVertex srcTree srcVertex } {
+ $destTree SetAll $destVertex [$srcTree Get $srcVertex]
+}
+##
+# A simple function that can be passed to MapDepthFirst to
+# print out a vertex and all of its fields
+#
+proc Print { graph vertex { lvl -1 } } {
+ # Print fields of vertex
+ puts "$vertex->[$graph GetOutAdjacencies $vertex]"
+ puts "$vertex<-[$graph GetInAdjacencies $vertex]"
+ foreach { f v } [$graph Get $vertex] {
+ PrintTabs $lvl
+ puts "$f = $v"
+ }
+}
+
+proc compareVerts { g field v1 v2 } {
+ return [string compare [$g Get $v1 $field] [$g Get $v2 $field]]
+}
+proc SortVertListByField { g L field { comp compareVerts } } {
+# proc compare { v1 v2 } \
+# "return [string compare [$g Get \$v1 $field] [$g Get \$v2 $field]]"
+ return [lsort -command "$comp $g $field " $L]
+}
+
+proc SortOutAjacencies { graphName v field { comp compareVerts } } {
+ upvar 0 Graph::$graphName g
+ set g($v) [$graphName SortVertListByField \
+ [$graphName GetOutAdjacencies $v] \
+ $field \
+ $comp]
+ return $g($v)
+}
+
+} ;# End Graph namespace
+
+IfStandAlone { ;# Some test code
+
+set T [Graph::Create { name }] ;# Create a graph where each vertex has a 'name' field
+set n1 [$T InsertVertex]
+$T Set $n1 name HOWDY
+
+# Insert a vertex and initialize its name in one call
+set n2 [$T InsertVertex { name DOODY }]
+$T AddEdge $n1 $n2
+
+# Insert an unitialized vertex
+set n3 [$T InsertVertex]
+# Set a field of a vertex
+$T Set $n3 name JUDY
+$T AddEdge $n2 $n3
+
+set n4 [$T InsertVertex { name TEX } ]
+$T AddEdge $n1 $n4
+
+set n5 [$T InsertVertex { name MEX } ]
+$T AddEdge $n1 $n5
+
+set n6 [$T InsertVertex { name aaa } ]
+$T AddEdge $n1 $n6
+
+$T SortOutAjacencies $n1 name
+
+# Print the graph
+$T MapBreadthFirst $n1 Graph::Print
+
+# Delete a vertex
+$T DeleteVertex $n3
+puts "---------------------"
+
+$T Map Graph::Print
+
+puts "---------------------"
+
+}
diff --git a/dmgen-1.0.0/src/htmlout.tcl b/dmgen-1.0.0/src/htmlout.tcl
new file mode 100644
index 0000000..8056558
--- /dev/null
+++ b/dmgen-1.0.0/src/htmlout.tcl
@@ -0,0 +1,376 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Code to write a datamap nicely formatted in HTML
+#
+# Requires:
+# pushd, popd
+# datamap.tcl
+# util.tcl
+# graph.tcl
+
+namespace eval DmGenHtmlOut {
+
+# a simple hack to write out a string in HTML with proper escapes
+proc EscapeHtmlString { s } {
+ set s [join [split $s "<"] "<"]
+ set s [join [split $s ">"] ">"]
+
+ return $s
+}
+proc startHtmlDoc { fd { title "" } } {
+ puts $fd ""
+ puts $fd " "
+ puts $fd " $title"
+ puts $fd " "
+ puts $fd " "
+}
+proc endHtmlDoc { fd } {
+ puts $fd " "
+ puts $fd ""
+}
+proc startFrameHtmlDoc { fd { title "" } } {
+ puts $fd ""
+ puts $fd " "
+ puts $fd " $title"
+ puts $fd " "
+}
+proc endFrameHtmlDoc { fd } {
+ puts $fd ""
+}
+
+##
+# Write an HTML datamap to directory fn
+proc WriteHtmlDatamap { fn dm } {
+ pushd $fn
+
+ writeHtmlIndex "Datamap: [Datamap::GetName $dm]"
+ writeHtmlToc $dm
+
+ set pss [lsort [Datamap::GetProblemSpaces $dm]]
+ set ops [lsort [Datamap::GetOperators $dm]]
+ foreach h [concat $pss $ops] {
+ writeHtmlPsOrOp $h
+ }
+
+ popd ;# pop back to original directory
+}
+
+proc writeHtmlIndex { title } {
+ set fd [open "index.html" w]
+
+ startFrameHtmlDoc $fd $title
+ puts $fd ""
+
+ endFrameHtmlDoc $fd
+
+ close $fd
+}
+proc writeHtmlToc { dm } {
+ set fd [open "toc.html" w]
+
+ startHtmlDoc $fd "Table of Contents"
+
+ puts $fd ""
+ puts $fd "
"
+
+ endHtmlDoc $fd
+ endValsFile
+ endProdsFile
+
+ close $fd
+}
+proc startValsFile { h } {
+ global ValsPsOrOp
+ set ValsPsOrOp $h
+}
+proc reallyStartValsFile { } {
+ global ValsPsOrOp ValsFd ValsFileName
+
+ set h $ValsPsOrOp
+
+ set name [Datamap::GetPsOrOpName $h]
+ if [Datamap::IsProblemSpace $h] {
+ set typeName "Problem Space"
+ set type S
+ } else {
+ set typeName "Operator"
+ set type O
+ }
+ set ValsFileName "$type-$name-vals.html"
+ set ValsFd [open $ValsFileName w]
+ startHtmlDoc $ValsFd "$typeName $name - Values"
+
+ puts $ValsFd "
Over-run values for $typeName $name
"
+}
+
+proc appendToValsFile { attr vals } {
+ global ValsFd ValsFileName
+ if ![info exists ValsFd] {
+ reallyStartValsFile
+ }
+ set tag [GetTag valTag]
+ set fd $ValsFd
+
+
+ puts $fd ""
+ puts $fd "
"
+ }
+
+ foreach v $out {
+ set name [$graph Get $v name]
+ if { !$HtmlVisited($v) } { ;# we haven't hit this vertex yet
+ if { [lsearch -exact [DmGenCfg::Get HtmlSuppressedAttributes] $name] == -1 } {
+ set depth 0
+ if { $name == "next" } {
+ set depth [getSoarListDepth $graph $v]
+ }
+ if { $depth > [DmGenCfg::Get HtmlMaxSoarListDepth] } {
+ puts $fd " ... Suppressed soarList with depth = $depth ... "
+ } else {
+ writeHtmlDatamap_r $fd $graph $v
+ }
+ }
+ } else {
+ puts $fd " ...Backedge to attribute $name..."
+ }
+ }
+ if { $show } {
+ puts $fd "
"
+ }
+}
+} ;# namespace DmgenHtmlOut
diff --git a/dmgen-1.0.0/src/lexer.tcl b/dmgen-1.0.0/src/lexer.tcl
new file mode 100644
index 0000000..9d5300e
--- /dev/null
+++ b/dmgen-1.0.0/src/lexer.tcl
@@ -0,0 +1,575 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Soar lexer.
+#
+# Proc exports:
+# get_lexeme
+#
+# Globals:
+# lexeme_value
+# lexeme_type
+
+
+proc initialize_file_scan {fd} {
+ global lexeme_value lexeme_type current_char file_buffer
+ set lexeme_value {}
+ set lexeme_type {}
+ set current_char { }
+ # global file_buffer must be set by caller before any calls
+ # to this module!
+}
+
+proc get_lexeme {} {
+ global lexeme_value lexeme_type current_char whitespace lexer_routine
+ global constituent_chars
+ set lexeme_value {}
+ set lexeme_type {}
+ while 1 {
+ if ![string compare $current_char {EOF}] break;
+ if [regexp \[$whitespace\] $current_char] {
+ get_next_char
+ continue
+ }
+ if ![string compare $current_char {;}] {
+ get_next_char
+ continue
+ }
+ if ![string compare $current_char {#}] {
+ while {[string compare $current_char "\n"] && \
+ [string compare $current_char {EOF}]} {
+ get_next_char
+ }
+ if [string compare $current_char {EOF}] {
+ get_next_char
+ }
+ continue
+ }
+ ## no whitespace found
+ break
+ }
+ if ![string compare $current_char {EOF}] {
+ lex_eof
+ } elseif [info exists lexer_routine("$current_char")] {
+ eval $lexer_routine("$current_char")
+ } elseif [regexp {[0-9]} $current_char] {
+ lex_digit
+ } elseif [regexp \[$constituent_chars\] $current_char] {
+ lex_constituent_string
+ } else {
+ lex_unknown
+ }
+ if 0 {
+ if ![string compare $current_char {EOF}] {
+ lex_eof
+ } elseif [info exists lexer_routine("$current_char")] {
+ eval $lexer_routine("$current_char")
+ } elseif [regexp \[$constituent_chars\] $current_char] {
+ lex_constituent_string
+ } elseif [regexp {[0-9]} $current_char] {
+ lex_digit
+ } else {
+ lex_unknown
+ }
+ }
+}
+
+proc get_next_char {} {
+ global current_char file_buffer
+ if {$file_buffer == ""} {
+ set current_char "EOF"
+ } else {
+ set current_char [string index $file_buffer 0]
+ set file_buffer [string range $file_buffer 1 end]
+
+ global parsing_function parsed_function
+ if { $parsing_function > 0 } {
+ set parsed_function "$parsed_function$current_char"
+ }
+ }
+}
+
+proc lex_eof {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type "EOF"
+}
+
+proc lex_at {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type at
+}
+
+proc lex_tilde {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type tilde
+}
+
+proc lex_up_arrow {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type up_arrow
+}
+
+proc lex_lbrace {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type l_brace
+}
+
+proc lex_rbrace {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type r_brace
+}
+
+proc lex_exclamation_point {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type exclamation_point
+}
+
+proc lex_comma {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type comma
+}
+
+proc lex_equal {} {
+ global lexeme_type lexeme_value
+ read_constituent_string
+ if {[string length $lexeme_value] == 1} {
+ set lexeme_type equal
+ return
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_ampersand {} {
+ global lexeme_type lexeme_value
+ read_constituent_string
+ if {[string length $lexeme_value] == 1} {
+ set lexeme_type ampersand
+ return
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_lparen {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type l_paren
+}
+
+proc lex_rparen {} {
+ global lexeme_type
+ store_and_advance
+ set lexeme_type r_paren
+}
+
+proc lex_greater {} {
+ global lexeme_type lexeme_value
+ read_constituent_string
+ if {[string length $lexeme_value] == 1} {
+ set lexeme_type greater
+ return
+ }
+ if {$lexeme_value == ">>"} {
+ set lexeme_type greater_greater
+ return
+ }
+ if {$lexeme_value == ">="} {
+ set lexeme_type greater_equal
+ return
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_less {} {
+ global lexeme_type lexeme_value
+ read_constituent_string
+ if {[string length $lexeme_value] == 1} {
+ set lexeme_type less
+ return
+ }
+ if {$lexeme_value == "<>"} {
+ set lexeme_type not_equal
+ return
+ }
+ if {$lexeme_value == "<="} {
+ set lexeme_type less_equal
+ return
+ }
+ if {$lexeme_value == "<<"} {
+ set lexeme_type less_less
+ return
+ }
+ if {$lexeme_value == "<=>"} {
+ set lexeme_type less_equal_greater
+ return
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_period {} {
+ global lexeme_type lexeme_value current_char
+ store_and_advance
+ if [regexp {[0-9]} $current_char] {
+ read_rest_of_floating_point_number
+ }
+ if {[string length $lexeme_value] == 1} {
+ set lexeme_type period
+ return
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_plus {} {
+ global current_char lexeme_value lexeme_type
+ read_constituent_string
+ if {$current_char == "."} {
+ set could_be_floating_point 1
+ foreach i [split [string range $lexeme_value 1 end]] {
+ if ![regexp {[0-9]} $i] {
+ set could_be_floating_point 0
+ }
+ }
+ if $could_be_floating_point {
+ read_rest_of_floating_point_number
+ }
+ }
+ if {[string length $lexeme_value] == 1} {
+ set lexeme_type plus
+ return
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_minus {} {
+ global current_char lexeme_value lexeme_type
+ read_constituent_string
+ if {$current_char == "."} {
+ set could_be_floating_point 1
+ foreach i [split [string range $lexeme_value 1 end]] {
+ if ![regexp {[0-9]} $i] {
+ set could_be_floating_point 0
+ }
+ }
+ if $could_be_floating_point {
+ read_rest_of_floating_point_number
+ }
+ }
+ if {[string length $lexeme_value] == 1} {
+ set lexeme_type minus
+ return
+ }
+ if {$lexeme_value == "-->"} {
+ set lexeme_type right_arrow
+ return
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_digit {} {
+ global current_char lexeme_value lexeme_type
+ read_constituent_string
+ if {$current_char == "."} {
+ set could_be_floating_point 1
+ foreach i [split [string range $lexeme_value 1 end]] {
+ if ![regexp {[0-9]} $i] {
+ set could_be_floating_point 0
+ }
+ }
+ if $could_be_floating_point {
+ read_rest_of_floating_point_number
+ }
+ }
+ determine_type_of_constituent_string
+}
+
+proc lex_unknown {} {
+ global current_char
+ parseError "Unknown character encountered by lexer '$current_char'"
+ get_next_char
+ get_lexeme
+}
+
+proc lex_constituent_string {} {
+ read_constituent_string
+ determine_type_of_constituent_string
+}
+
+proc lex_vbar {} {
+ global lexeme_type lexeme_value current_char
+ set lexeme_type sym_constant
+ get_next_char
+ while 1 {
+ if {$current_char == "EOF"} {
+ parseError "Opening '|' without closing '|'"
+ set lexeme_type "EOF"
+ return
+ }
+ if {$current_char == "\\"} {
+ get_next_char
+ set lexeme_value [format "%s%s" $lexeme_value $current_char]
+ get_next_char
+ } elseif {$current_char == "|"} {
+ get_next_char
+ break
+ } else {
+ set lexeme_value [format "%s%s" $lexeme_value $current_char]
+ get_next_char
+ }
+ }
+}
+
+proc lex_quote {} {
+ global lexeme_type lexeme_value current_char
+ set lexeme_type quoted_string
+ get_next_char
+ while 1 {
+ if {$current_char == "EOF"} {
+ parseError "Opening '\"' without closing '\"'"
+ set lexeme_type "EOF"
+ return
+ }
+ if {$current_char == "\\"} {
+ get_next_char
+ set lexeme_value [format "%s%s" $lexeme_value $current_char]
+ get_next_char
+ } elseif {$current_char == "\""} {
+ get_next_char
+ break
+ } else {
+ set lexeme_value [format "%s%s" $lexeme_value $current_char]
+ get_next_char
+ }
+ }
+}
+
+proc lex_dollar {} {
+ global lexeme_type lexeme_value current_char
+ set lexeme_type dollar_string
+ set lexeme_value "$"
+ get_next_char
+ while {($current_char != "\n") && ($current_char != "EOF")} {
+ set lexeme_value [format "%s%s" $lexeme_value $current_char]
+ get_next_char
+ }
+}
+
+proc read_rest_of_floating_point_number {} {
+ global current_char
+ store_and_advance
+ while {[regexp {[0-9]} $current_char]} {
+ store_and_advance
+ }
+ if {($current_char == "e") || ($current_char == "E")} {
+ store_and_advance
+ if {($current_char == "+") || ($current_char == "-")} {
+ store_and_advance
+ }
+ while {[regexp {[0-9]} $current_char]} {
+ store_and_advance
+ }
+ }
+}
+
+proc read_constituent_string {} {
+ global constituent_chars current_char
+ while {($current_char != "EOF") && \
+ [regexp \[$constituent_chars\] $current_char]} {
+ store_and_advance
+ }
+}
+
+proc store_and_advance {} {
+ global lexeme_value current_char
+ set lexeme_value [format "%s%s" $lexeme_value [string tolower $current_char]]
+ get_next_char
+}
+
+proc determine_type_of_constituent_string {} {
+ global lexeme_value lexeme_type
+ set s [determine_possible_symbol_types_for_string [split $lexeme_value ""]]
+ if {[lsearch $s possible_var] >= 0} {
+ set lexeme_type variable
+ return
+ }
+ if {[lsearch $s possible_ic] >= 0} {
+ set lexeme_type int_constant
+ return
+ }
+ if {[lsearch $s possible_fc] >= 0} {
+ set lexeme_type float_constant
+ return
+ }
+ # For now we will always have this as 0, because we are just interested
+ # in productions (which do not contain identifiers), but if we want
+ # to care about other commands someday, we can use this code
+ set allow_ids 0
+ if {$allow_ids && ([lsearch $s possible_id] >= 0)} {
+ set lexeme_type identifier
+ return
+ }
+ if {[lsearch $s possible_sc] >= 0} {
+ set lexeme_type sym_constant
+ if {[string index $lexeme_value 0] == "<"} {
+ if {[string index $lexeme_value 1] == "<"} {
+ parseError "Warning: Possible disjunct intended but interpreted as symbolic constant"
+ } else {
+ parseError "Warning: Possible variable intended but interpreted as symbolic constant"
+ }
+ } else {
+ if {[string index $lexeme_value [expr [string length $lexeme_value] - 1]] == ">"} {
+ if {[string index $lexeme_value [expr [string length $lexeme_value] - 2]] == ">"} {
+ parseError "Warning: Possible disjunct intended but interpreted as symbolic constant"
+ } else {
+ parseError "Warning: Possible variable intended but interpreted as symbolic constant"
+ }
+ }
+ }
+ return
+ }
+ set lexeme_type quoted_string
+}
+
+proc determine_possible_symbol_types_for_string {s} {
+ global number_starters constituent_chars
+ set retval ""
+ if [regexp \[$number_starters\] [lindex $s 0]] {
+ set i 0
+ if {([lindex $s 0] == "+") || ([lindex $s 0] == "-")} {
+ incr i
+ }
+ while {[regexp {[0-9]} [lindex $s $i]]} {
+ incr i
+ }
+ if {([lindex $s $i] == "") && \
+ [regexp {[0-9]} [lindex $s [expr $i - 1]]]} {
+ lappend retval possible_ic
+ }
+ if {[lindex $s $i] == "."} {
+ incr i
+ while {[regexp {[0-9]} [lindex $s $i]]} {
+ incr i
+ }
+ if {([lindex $s $i] == "e") || ([lindex $s $i] == "E")} {
+ incr i
+ if {([lindex $s $i] == "+") || ([lindex $s $i] == "-")} {
+ incr i
+ }
+ while {[regexp {[0-9]} [lindex $s $i]]} {
+ incr i
+ }
+ }
+ if {[lindex $s $i] == ""} {
+ lappend retval possible_fc
+ }
+ }
+ }
+ for {set i 0} {[lindex $s $i] != ""} {incr i} {
+ if ![regexp \[$constituent_chars\] [lindex $s $i]] {
+ return $retval
+ }
+ }
+ lappend retval possible_sc
+ if {([lindex $s 0] == "<") && \
+ ([lindex $s [expr [llength $s] - 1]] == ">")} {
+ lappend retval possible_var
+ }
+ if [regexp {[A-Za-z]} [lindex $s 0]] {
+ set i 1
+ while {[regexp {[0-9]} [lindex $s $i]]} {
+ incr i
+ }
+ if {([lindex $s $i] == "") && \
+ [regexp {[0-9]} [lindex $s [expr $i - 1]]]} {
+ lappend retval possible_id
+ }
+ }
+ return $retval
+}
+
+proc discard_line {} {
+ global file_buffer
+ set file_buffer ""
+}
+
+#############################
+
+initialize_file_scan ""
+
+global constituent_chars whitespace number_starters
+set constituent_chars "A-Za-z0-9$%&*+/:<=>?_-"
+set whitespace " \f\n\r\t\v"
+set number_starters "0-9+\-."
+
+global lexer_routine
+set lexer_routine("@") lex_at
+set lexer_routine("(") lex_lparen
+set lexer_routine(")") lex_rparen
+set lexer_routine("+") lex_plus
+set lexer_routine("-") lex_minus
+set lexer_routine("~") lex_tilde
+set lexer_routine("^") lex_up_arrow
+set lexer_routine("{") lex_lbrace
+set lexer_routine("}") lex_rbrace
+set lexer_routine("!") lex_exclamation_point
+set lexer_routine(">") lex_greater
+set lexer_routine("<") lex_less
+set lexer_routine("=") lex_equal
+set lexer_routine("&") lex_ampersand
+set lexer_routine("|") lex_vbar
+set lexer_routine(",") lex_comma
+set lexer_routine(".") lex_period
+set lexer_routine("\"") lex_quote
+set lexer_routine("$") lex_dollar
+
+# just a function for debugging the lexer
+proc testLex { s } {
+ global file_buffer current_char lexeme_type lexeme_value
+ set file_buffer $s
+ set current_char { }
+ set lexeme_type ""
+ while { $lexeme_type != "EOF" } {
+ get_lexeme
+ puts "Lexeme: $lexeme_type, $lexeme_value"
+ }
+}
diff --git a/dmgen-1.0.0/src/log.tcl b/dmgen-1.0.0/src/log.tcl
new file mode 100644
index 0000000..5cbef37
--- /dev/null
+++ b/dmgen-1.0.0/src/log.tcl
@@ -0,0 +1,143 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# A simple set of logging functions. Sends output to stdout as well as a
+# file in the current directory (created at the time of the
+# first Log call)
+
+set LogAutoFlush 0 ;# if true, then every log write is flushed to disk
+set LogFileName "" ;# name of file to write to
+
+proc LogSetFileName { fileName } {
+ global LogFileName
+ LogReset
+ set LogFileName $fileName
+}
+
+proc doLog { prefix s log } {
+ global LogAutoFlush
+ set s "$prefix $s"
+ puts $s
+ if { $log != -1 } {
+ puts $log $s
+ if { $LogAutoFlush } {
+ flush $log
+ }
+ }
+}
+
+##
+# Log an error
+proc LogError { s } {
+ doLog "*** ERROR: " $s [getLogFileId]
+}
+
+##
+# Log a warning
+proc LogWarning { s } {
+ doLog "--- WARNING: " $s [getLogFileId]
+}
+
+##
+# Log info
+proc LogInfo { s } {
+ doLog "--- INFO: " $s [getLogFileId]
+}
+
+##
+# Write an arbitrary string to the log
+proc Log { s { newLine 1 } } {
+ set log [getLogFileId]
+
+ if { $newLine } {
+ puts $s
+ if { $log != -1 } {
+ puts $log $s
+ }
+ } else {
+ puts -nonewline $s
+ if { $log != -1 } {
+ puts -nonewline $log $s
+ }
+ }
+ global LogAutoFlush
+ if { $log != -1 && $LogAutoFlush } {
+ flush $log
+ }
+}
+##
+# Flush the log to disk
+proc LogFlush { } {
+ global LogFileId
+ if [info exists LogFileId] {
+ flush $LogFileId
+ }
+}
+
+##
+# Reset the log file.
+proc LogReset { } {
+ global LogFileId
+
+ if [info exists LogFileId] {
+ close $LogFileId
+ unset LogFileId
+ }
+}
+##
+# Set the value of the auto-flush parameter
+proc LogSetAutoFlush { b } {
+ global LogAutoFlush
+
+ set LogAutoFlush $b
+}
+
+##
+# internal function to open log file.
+proc getLogFileId {} {
+ global LogFileId LogFileName
+
+ if ![info exists LogFileId] {
+ if { $LogFileName == "" } {
+ return -1
+ }
+ set LogFileId [open $LogFileName w]
+ puts $LogFileId ""
+ puts $LogFileId "#################### LOG OPENED ##########################"
+ }
+ return $LogFileId
+}
diff --git a/dmgen-1.0.0/src/merge.tcl b/dmgen-1.0.0/src/merge.tcl
new file mode 100644
index 0000000..f035d0c
--- /dev/null
+++ b/dmgen-1.0.0/src/merge.tcl
@@ -0,0 +1,224 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Code for merging a production into a datamap...
+#
+# Requires:
+# config.tcl
+# datamap.tcl
+# graph.tcl
+
+##
+# Process a partitioned production, merging it into the appropriate
+# problem spaces and operators of the passed datamap.
+#
+# @param dm Datamap to fill
+# @param name Name of source production
+# @param graph Production graph
+# @param part Partition info returned by PartitionProduction
+proc ProcessProd { dm name graph part } {
+ # $part is a list of 4-tupes...
+ foreach { type pss state p } $part {
+ if { $type == "S" } { ;# it's a problem space
+ foreach ps $pss { ;# for each destination problem space
+ set h [Datamap::FindOrCreateProblemSpace $dm $ps]
+ set hGraph [Datamap::GetGraph $h]
+ set hStart [Datamap::GetStartVertex $h]
+
+ MergeProdIntoDatamap $name $graph $state $p \
+ $hGraph \
+ $hStart
+ }
+ } else { ;# it's an operator
+ foreach op $pss { ;# for each named operator
+ set h [Datamap::FindOrCreateOperator $dm $op]
+ set hGraph [Datamap::GetGraph $h]
+ set hStart [Datamap::GetStartVertex $h]
+ MergeProdIntoDatamap $name $graph $state $p \
+ $hGraph \
+ $hStart
+ }
+ }
+ }
+}
+
+##
+# Merge a partitioned production into a particular problem space or
+# operator graph.
+# This is just a setup function. The real work is done in the recursive
+# mergeProdIntoDatamap function.
+#
+# @param pName Name of production
+# @param pGraph Production graph
+# @param pState 'state' or 'operator' vertex of production
+# @param part Production partition info
+# @param dmGraph Target ps or op graph
+# @param dmState 'state' or 'operator' vertex of ps or op
+proc MergeProdIntoDatamap { pName pGraph pState part dmGraph dmState } {
+ global gMergeMap gMergeParts
+ if [info exists gMergeMap] { unset gMergeMap }
+ if [info exists gMergeParts] { unset gMergeParts }
+ foreach { v ps } $part {
+ set gMergeMap($v) [Graph::NullVertex]
+ set gMergeParts($v) $ps ;# external PS links
+ }
+ mergeProdIntoDatamap $pName $pGraph $pState $dmGraph $dmState
+}
+
+##
+# Merge a partitioned production into a particular problem space or
+# operator graph. Performs a simultaneous depth-first traversal of
+# the production graph and the datamap graph, filling in the datamap
+# graph as necessary.
+#
+# Uses two global variables (gMergeMap and gMergeParts) initialized
+# by MergeProdIntoDatamap to keep track of where it's been (to avoid
+# cycles) and to make links when the boundary of a partition is
+# reached. gMergeMap is a map from production vertex to datamap vertex.
+#
+# @param pName Name of production
+# @param pGraph Production graph
+# @param pTag current production vertex
+# @param dmGraph Target ps or op graph
+# @param dmTag current ps or op vertex
+proc mergeProdIntoDatamap { pName pGraph pTag dmGraph dmTag } {
+ global gMergeMap gMergeParts
+
+ set NV [Graph::NullVertex] ;# cache NullVertex value
+ set dmOut [$dmGraph GetOutAdjacencies $dmTag]
+ foreach v [$pGraph GetOutAdjacencies $pTag] {
+ # Have we been here before? Let's avoid cycles...
+ # Is this the coorect thing to do?
+ if { [info exists gMergeMap($v)] } {
+ set dv $gMergeMap($v)
+ if { $dv != $NV } {
+ $dmGraph AddEdge $dmTag $dv ;# just add an edge
+ continue
+ }
+ }
+ set name [$pGraph Get $v name]
+# puts "M $name"
+ set dv [$dmGraph FindVertex name $name $dmOut]
+ if { $dv != $NV } { ;# DM already has this node...
+
+ set gMergeMap($v) $dv ;# update merge map
+
+ set pt [$pGraph Get $v type]
+ set dmt [$dmGraph Get $dv type]
+ if { $pt != $dmt } {
+ if { $dmt == "unknown" } {
+ # here we know that $pt != "unknown" so it's a better choice
+ # for the type, set it.
+ $dmGraph Set $dv type $pt
+ } elseif { $pt == "unknown" } {
+ # here we know that $dt != "unknown" so it's a better choice
+ # for the type, keep it.
+ } else {
+ # neither type is unknown, but they're in conflict,
+ # we'll just log it for now since it's hard to know
+ # which is the better guess for the type.
+ LogWarning "Non-matching data types! $pt != $dmt, $name"
+ }
+ }
+
+ $dmGraph Set $dv special [lunion [$dmGraph Get $dv special] \
+ [$pGraph Get $v special]]
+
+ $dmGraph Set $dv value [lunion [$dmGraph Get $dv value] \
+ [$pGraph Get $v value]]
+
+ $dmGraph Set $dv side [Production::MergeSideValues \
+ [$dmGraph Get $dv side] \
+ [$pGraph Get $v side]]
+
+ if { [DmGenCfg::Get SaveSourceProds] } {
+ $dmGraph Set $dv prods [lunion [$dmGraph Get $dv prods] $pName]
+ }
+
+ set l [$dmGraph Get $dv link]
+ # If there is a known link, add it.
+ if { [info exists gMergeParts($v)] } {
+ # WARN: This is a little dangerous...it relies on the fact that
+ # lunion preserves some order, i.e. that the link type (O or S)
+ # will still be the first element after the union is done.
+ # bad bad bad.
+ $dmGraph Set $dv link [lunion $l $gMergeParts($v)]
+ }
+ # Recursively merge this branch of the graph.
+ # This isn't an else because in some productions we may have been able
+ # to determine a link, but in others we may not have. Think of a
+ # production that puts attributes on the operator without testing the
+ # name of the operator.
+ mergeProdIntoDatamap $pName $pGraph $v $dmGraph $dv
+
+ # Edge is missing from DM, or node doesn't exist
+ # Make sure that this vertex is in the current partition (don't
+ # follow links)
+ } elseif { [info exists gMergeMap($v)] } {
+ set dv $gMergeMap($v)
+ if { $dv != $NV } { ;# Backedge, we've already seen $v and $dv before.
+ $dmGraph AddEdge $dmTag $dv ;# just add a vertex
+ } else {
+ # Create a new vertex in the datamap
+ set special [$pGraph Get $v special]
+ set type [$pGraph Get $v type]
+ set value [$pGraph Get $v value]
+ set side [$pGraph Get $v side]
+ set dv [$dmGraph InsertVertex [Datamap::DefVertexFields]]
+ $dmGraph SetL $dv [list name $name \
+ type $type \
+ side $side \
+ value $value \
+ special $special \
+ link $gMergeParts($v)]
+
+ if { [DmGenCfg::Get SaveSourceProds] } {
+ $dmGraph Set $dv prods $pName
+ }
+
+ $dmGraph AddEdge $dmTag $dv
+ set gMergeMap($v) $dv ;# update merge map
+
+ # Are we at the boundary of a partition? If not, keep going
+ # by recursively following this graph branch.
+ if { $gMergeParts($v) == {} } {
+ mergeProdIntoDatamap $pName $pGraph $v $dmGraph $dv
+ }
+ }
+ }
+ }
+}
diff --git a/dmgen-1.0.0/src/parser.tcl b/dmgen-1.0.0/src/parser.tcl
new file mode 100644
index 0000000..7dc4183
--- /dev/null
+++ b/dmgen-1.0.0/src/parser.tcl
@@ -0,0 +1,443 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Soar production "parser".
+#
+# Proc exports:
+# parse_production
+
+proc parse_production { buf } {
+ global file_buffer
+ set file_buffer $buf
+ global current_char
+ set current_char " "
+ global productionName lexeme_type lexeme_value
+ get_lexeme
+ if {($lexeme_type != "sym_constant") || ($lexeme_value != "sp")} {
+ parseError "Production must start with sp"
+ return 0
+ }
+ get_lexeme
+ if {$lexeme_type != "l_brace"} {
+ parseError "Production definition must begin with \{"
+ return 0
+ }
+ get_lexeme
+ if {$lexeme_type != "sym_constant"} {
+ parseError "Expected symbol for production name"
+ return 0
+ }
+ set productionName $lexeme_value
+ get_lexeme
+ if {$lexeme_type == "quoted_string"} {
+ get_lexeme
+ }
+ while 1 {
+ if {$lexeme_type != "sym_constant"} {
+ break
+ }
+ if {($lexeme_value == ":o-support") || \
+ ($lexeme_value == ":i-support") || ($lexeme_value == ":chunk") || \
+ ($lexeme_value == ":default") || ($lexeme_value == ":justification")} {
+ get_lexeme
+ continue
+ }
+ break
+ }
+ set lhs [parse_lhs]
+ if {$lhs == 0} {
+ puts "parse_lhs failed"
+ return 0
+ }
+ if {$lexeme_type != "right_arrow"} {
+ parseError "Expected --> in production"
+ return 0
+ }
+ get_lexeme
+ set rhs [parse_rhs]
+ if {$rhs == 0} {
+ puts "parse_lhs failed"
+ return 0
+ }
+ if {$lexeme_type != "r_brace"} {
+ parseError "Expected \} to end production"
+ return 0
+ }
+ get_lexeme
+ if {$lexeme_type != "EOF"} {
+ parseError "Found text after production end?"
+ return 0
+ }
+ return [concat $lhs $rhs]
+}
+
+proc parse_lhs {} {
+ return [parse_cond_plus]
+}
+
+proc parse_cond_plus {} {
+ global lexeme_type
+ set c ""
+ for {set nc [parse_cond]} \
+ {($lexeme_type == "minus") || ($lexeme_type == "l_paren")} \
+ {set nc [parse_cond]} {
+ if {$nc == 0} {
+ return 0
+ }
+ set c [concat $c $nc]
+ }
+ if {$nc == 0} {
+ return 0
+ }
+ set c [concat $c $nc]
+ return $c
+}
+
+proc parse_cond {} {
+ global lexeme_type
+ if {$lexeme_type == "minus"} {
+ get_lexeme
+ }
+ if {$lexeme_type == "l_brace"} {
+ get_lexeme
+ set c [parse_cond_plus]
+ if {$c == 0} {
+ return 0
+ }
+ if {$lexeme_type != "r_brace"} {
+ parseError "Expected \} to end conjunctive condition"
+ return 0
+ }
+ get_lexeme
+ } else {
+ set c [parse_single_cond]
+ if {$c == 0} {
+ return 0
+ }
+ }
+ return $c
+}
+
+proc parse_single_cond {} {
+ global lexeme_type lexeme_value
+ if {$lexeme_type != "l_paren"} {
+ parseError "Expected ( to begin condition"
+ return 0
+ }
+ get_lexeme
+ set headElement ""
+ if {$lexeme_type == "sym_constant"} {
+ if {($lexeme_value == "state") || ($lexeme_value == "impasse")} {
+ set headElement $lexeme_value
+ get_lexeme
+ }
+ }
+ if {$lexeme_type != "variable"} {
+ parseError "Expected variable for condition id test"
+ return 0
+ }
+ set id_test $lexeme_value
+ get_lexeme
+ if {$lexeme_type == "minus"} {
+ get_lexeme
+ }
+ if {$lexeme_type != "up_arrow"} {
+ parseError "Expected ^ to begin attribute test"
+ return 0
+ }
+
+ get_lexeme
+
+ global relational_test_types
+
+ set attr_test [parse_test]
+ if {$attr_test == {} } {
+ return 0
+ }
+ set attr_test_rels $relational_test_types
+ set value_test [parse_test]
+ if {$value_test == {} } {
+ return 0
+ }
+ set value_test_rels $relational_test_types
+
+ parse_preference ;# Make sure we get LHS operator preference
+ ;# Added by Dave Ray 05/02/2002
+
+ if {$lexeme_type != "r_paren"} {
+ parseError "Expected ) to end condition"
+ return 0
+ }
+ get_lexeme
+ set c ""
+ if {$headElement != ""} {
+ lappend c [list L "TOP" $headElement $id_test \
+ $attr_test_rels $value_test_rels]
+ }
+ foreach i $attr_test {
+ foreach j $value_test {
+ lappend c [list L \
+ $id_test \
+ $i $j \
+ $attr_test_rels $value_test_rels]
+ }
+ }
+ return $c
+}
+
+proc parse_test {} {
+ global lexeme_type relational_test_types
+ set relational_test_types {}
+ if {$lexeme_type != "l_brace"} {
+ return [parse_simple_test]
+ }
+ get_lexeme
+ set c ""
+ for {set r [parse_simple_test]} {$lexeme_type != "r_brace"} \
+ {set r [parse_simple_test]} {
+ if {$r == {} } {
+ return $r
+ }
+ set c [concat $c $r]
+ }
+ if {$r == {} } {
+ return $r
+ }
+ set c [concat $c $r]
+ get_lexeme
+ return $c
+}
+
+proc parse_simple_test {} {
+ global lexeme_type
+ if {$lexeme_type == "less_less"} {
+ return [parse_disjunction_test]
+ } else {
+ return [parse_relational_test]
+ }
+}
+
+proc parse_disjunction_test {} {
+ global lexeme_type lexeme_value
+ if {$lexeme_type != "less_less"} {
+ parseError "Expected << to begin disjunction test"
+ return {}
+ }
+ set c ""
+ for {get_lexeme} {$lexeme_type != "greater_greater"} {get_lexeme} {
+ if {($lexeme_type != "sym_constant") && \
+ ($lexeme_type != "int_constant") && \
+ ($lexeme_type != "float_constant")} {
+ parseError "Expected constant or >> while reading disjunction test"
+ return {}
+ }
+ lappend c $lexeme_value
+ }
+ get_lexeme
+ return $c
+}
+
+proc parse_relational_test {} {
+ global lexeme_type lexeme_value relational_test_types
+ if {($lexeme_type == "equal") || ($lexeme_type == "not_equal") || \
+ ($lexeme_type == "less") || ($lexeme_type == "greater") || \
+ ($lexeme_type == "less_equal") || ($lexeme_type == "greater_equal") || \
+ ($lexeme_type == "less_equal_greater")} {
+ lappend relational_test_types $lexeme_type
+
+ get_lexeme
+ }
+ if {($lexeme_type == "sym_constant") || ($lexeme_type == "int_constant") || \
+ ($lexeme_type == "float_constant") || ($lexeme_type == "variable")} {
+ set c $lexeme_value
+ get_lexeme
+ return $c
+ # This is a special weird case that occurs when a production tests an
+ # attribute for the empty string ||. In this case, print -internal prints
+ # the value, but since it's the empty string it doesn't appear as anything.
+ # Annoying...
+ } elseif { $lexeme_type == "r_paren" } {
+ return "____DMGEN_EMPTYSTRING____" ;
+ # Can't just return "" because that's the error return code :(
+ # Stupid tcl.
+ } else {
+ parseError "Expected variable or constant for test"
+ return {}
+ #return 0
+ }
+}
+
+proc parse_rhs {} {
+ global lexeme_type
+ set c ""
+ while {$lexeme_type != "r_brace"} {
+ set nc [parse_rhs_action]
+ if {$nc == 0} {
+ return 0
+ }
+ set c [concat $c $nc]
+ }
+ return $c
+}
+
+proc parse_rhs_action {} {
+ global lexeme_type lexeme_value
+ if {$lexeme_type != "l_paren"} {
+ parseError "Expected ( to begin RHS action"
+ return 0
+ }
+ get_lexeme
+ if {$lexeme_type != "variable"} {
+ if {[parse_function_call_after_lparen] == {} } {
+ return 0
+ }
+ return ""
+ }
+ set id_make $lexeme_value
+ get_lexeme
+ if {$lexeme_type != "up_arrow"} {
+ parseError "Expected ^ in RHS action attribute"
+ return 0
+ }
+ get_lexeme
+ set attr_make [parse_rhs_value]
+ if {$attr_make == {} } {
+ return 0
+ }
+ set value_make [parse_rhs_value]
+ set alt_value_make [parse_preference]
+ if {$lexeme_type != "r_paren"} {
+ parseError "Expected ) to end RHS action, got $lexeme_type"
+ return 0
+ }
+ get_lexeme
+ if {$alt_value_make == ""} {
+ return [list [list R $id_make $attr_make $value_make]]
+ } else {
+ return [list [list R $id_make $attr_make $value_make] \
+ [list R $id_make $attr_make $alt_value_make]]
+ }
+}
+
+# these are here just so we can store the text of a function call
+set parsing_function 0 ;# current parse_function... call depth
+set parsed_function "" ;# buffer where function call text is stored
+
+proc parse_function_call_after_lparen {} {
+ global lexeme_type lexeme_value
+
+ global parsing_function parsed_function
+ incr parsing_function ;# increment call depth
+ if { $parsing_function == 1 } {
+ # Initialize function buffer. The left paren and operator have
+ # already been parsed
+ set parsed_function "( $lexeme_value "
+ }
+
+ get_lexeme
+ while {$lexeme_type != "r_paren"} {
+ if { [parse_rhs_value] == {} } {
+ set parsing_function 0 ;# clean up call depth
+ set parsed_function ""
+ #return 0
+ return {}
+ }
+ }
+ incr parsing_function -1 ;# decrement call depth
+ get_lexeme
+ if { $parsing_function == 0 } { ;# done parsing function
+ return [list [list "FUNCTION" $parsed_function]]
+ }
+ return "FUNCTION_CALL?"
+}
+
+proc parse_rhs_value {} {
+ global lexeme_type lexeme_value
+ if {$lexeme_type == "l_paren"} {
+ get_lexeme
+ return [parse_function_call_after_lparen]
+ }
+ if {($lexeme_type == "sym_constant") || ($lexeme_type == "int_constant") || \
+ ($lexeme_type == "float_constant") || ($lexeme_type == "variable")} {
+ set c $lexeme_value
+ get_lexeme
+ return $c
+ }
+ parseError "Illegal value for RHS value"
+ #return 0
+ return {}
+}
+
+proc parse_preference {} {
+ global lexeme_type
+ set x [parse_preference_specifier_without_referent]
+ if {$x == "binary"} {
+ set c [parse_rhs_value]
+ if {$c == {} } {
+ return 0
+ }
+ return $c
+ }
+ return ""
+}
+
+proc parse_preference_specifier_without_referent {} {
+ global lexeme_type
+ if {($lexeme_type == "plus") || ($lexeme_type == "minus") || \
+ ($lexeme_type == "exclamation_point") || ($lexeme_type == "tilde") || \
+ ($lexeme_type == "at")} {
+ get_lexeme
+ return unary
+ }
+ if {($lexeme_type == "greater") || ($lexeme_type == "equal") || \
+ ($lexeme_type == "less") || ($lexeme_type == "ampersand")} {
+ get_lexeme
+ if {$lexeme_type != "r_paren"} {
+ return binary
+ }
+ return unary
+ }
+ return special
+}
+
+proc parseError {x} {
+ global file_buffer lexeme_type lexeme_value
+ LogError "Parse Error: $x, \
+lexeme_type = $lexeme_type, lexeme_value = $lexeme_value \
+### Remaining buffer:\n$file_buffer\n###"
+
+}
diff --git a/dmgen-1.0.0/src/partition.tcl b/dmgen-1.0.0/src/partition.tcl
new file mode 100644
index 0000000..0ffea97
--- /dev/null
+++ b/dmgen-1.0.0/src/partition.tcl
@@ -0,0 +1,240 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Code for partitioning a production graph into problem-spaces and operators.
+#
+# Requires:
+# util.tcl
+# production.tcl
+# config.tcl
+# log.tcl
+
+namespace eval Partition {
+
+##
+# Given a production graph and a state vertex, get a list of problem
+# spaces that that state refers to.
+#
+# The reason that this can return a list is because a production may
+# test more than one problem space name.
+#
+# @param graph Production graph
+# @param state State vertex
+# @returns A list of problem space names
+proc GetPsNames { graph state } {
+
+ if ![$graph Get $state isState] {
+ return {}
+ }
+
+ set special [$graph Get $state special]
+
+ # We route everything under a top-state attribute to the top-ps problem
+ # space
+ # CFG - topstate to top-ps?
+ if { [DmGenCfg::Get FillTopPs] && $special == "TopState" } {
+ return "top-ps"
+ }
+
+ # Search for children that test ^problem-space.name
+ set spec [Production::ProblemSpaceSpec]
+ set node $state
+ foreach s $spec {
+ set node [$graph FindVertex name $s [$graph GetOutAdjacencies $node]]
+ if { $node == [Graph::NullVertex] } {
+ break
+ }
+ }
+ if { $node != [Graph::NullVertex] } {
+ set psNames [$graph Get $node value] ;# list of problem-space names
+ # If they are testing for NOT a problem-space name, we assign it to
+ # any-ps. This is a bit of a hack, but a general solution for
+ # interpretting all relational operators in all tests is out of reach at
+ # the moment.
+ # an example of this would be:
+ # (state ^problem-space.name { <> waiting } )
+ if { [$graph Get $node valRelOps] == "not_equal" } {
+ set psNames "any-ps"
+ LogInfo "not_equal relation found on problem-space.name test, assigning to any-ps."
+ }
+ } elseif { [DmGenCfg::Get FillAnyPs] && $special != "SuperState" && $special != "TopState" } {
+ # A non-superstate that does not inspect problem-space.name goes to any-ps
+ # Since we have no idea what the superstate is, it would be stupid to stick
+ # that stuff on any-ps.
+ set psNames "any-ps"
+ } else {
+ set psNames {}
+ }
+
+ return $psNames
+}
+
+##
+# Like GetPsNames, except for operators. Given an operator attribute,
+# it finds all the names referenced by that operator.
+proc GetOpNames { graph op } {
+ set special [$graph Get $op special]
+ if { $special != "Operator" } {
+ return {}
+ }
+
+ # TODO This should use Production::OperatorSpec just like GetPsNames.
+ set node [$graph FindVertex name name [$graph GetOutAdjacencies $op]]
+ if { $node == [Graph::NullVertex] } {
+ return {}
+ }
+ set opNames [$graph Get $node value] ;# return list of operator names
+
+ # If they are testing for NOT an operator name, we treat it as if there
+ # was no operator named which means that any structure on the operator
+ # attribute will be copied into the problem-space where it's encountered.
+ # This is a bit of a hack, but a general solution for
+ # interpretting all relational operators in all tests is out of reach at
+ # the moment.
+ # an example of this would be:
+ # (state ^operator.name { <> waiting } )
+ if { [$graph Get $node valRelOps] == "not_equal" } {
+ LogInfo "not_equal relation found on operator.name test"
+ set opNames {}
+ }
+
+ return $opNames ;# return list of operator names
+}
+
+##
+# Partition a production graph into constituent problem spaces and operators.
+#
+# This gives us a way to merge the various parts of the production into the
+# correct problem spaces or operators in the datamap. If top-state is
+# tested, then everthing under that goes to top-ps. If there are multiple
+# states testing multiple problem space names, they will all go to the
+# correct place.
+#
+# Returns a list of tuples:
+# 1 = tag of state or operator vertex
+# 2 = type of vertex (S = problem space, O = operator)
+# 3 = list of problem-space or operator names
+# 4 = list of vertices that are part of that state or operator
+#
+# @param p Production graph
+# @returns The list of 4-tuples described above.
+proc PartitionProduction { p } {
+ set Parts {}
+ # For all identified states and operators in the production...
+ foreach s [concat [Production::GetStates $p] [Production::GetOperators $p]] {
+ if { [$p Get $s isState] } {
+ set type S
+ set psNames [GetPsNames $p $s]
+ } else { ;# s is an operator
+ set type O
+ set psNames [GetOpNames $p $s]
+ }
+ # If there were no problem spaces or operators found, we just ignore it.
+ # This should only happen if FillAnyPs is turned off!
+ if { $psNames == {} } { continue }
+
+ # Prepare for breadth first traversal...
+ foreach v [$p GetVertices] {
+ set visited($v) 0
+ }
+
+ set P {} ;# Current partition we're building
+
+ set L [$p GetOutAdjacencies $s] ;# traversal queue
+ set visited($s) 1
+ foreach v $L { set visited($v) 1 }
+
+ while { [llength $L] > 0 } {
+ set v [lindex $L 0] ;# Get head of queue
+ set L [lrange $L 1 end] ;# Pop head of queue
+
+ # If this is not a state with a problem space, or a named operator,
+ # we keep going, otherwise, we stop the partition here, it will
+ # become a link.
+ set vIsState [$p Get $v isState]
+ set vPsNames [GetPsNames $p $v]
+ set link {}
+ if { ![expr $vIsState && { $vPsNames != {} }] } {
+
+ # Is this a named operator?
+ set vIsOp [expr [string compare [$p Get $v special] "Operator"] == 0]
+ set vOpNames [GetOpNames $p $v]
+ if { ![expr $vIsOp && { $vOpNames != {} }] } {
+ foreach a [$p GetOutAdjacencies $v] {
+ if { !$visited($a) } {
+ set visited($a) 1
+ lappend L $a
+ }
+ }
+ } else { ;# it's a named operator
+ set link [concat O $vOpNames]
+ }
+ } else { ;#it's a named problem-space
+ set link [concat S $vPsNames]
+ }
+ lappend P $v $link ;# Add v to partition
+ }
+ lappend Parts $type $psNames $s $P ;# Add current partition to list of partitions
+ }
+ return $Parts
+}
+
+proc test { } {
+ sp { test
+ (state ^problem-space.name MyPs)
+ ( ^x 1)
+ ( ^y 5)
+ ( ^z 6)
+ ( ^superstate )
+ ( ^problem-space.name SsPs)
+ ( ^p 2 ^q 3 ^r 4)
+ ( ^operator )
+ ( ^name bob ^param howdy)
+ -->
+ ( ^p 5)
+ }
+
+ set g [Production::Parse test]
+ set p [PartitionProduction $g]
+}
+
+} ;# namespace
+
+IfStandAlone { ;# Some test code
+ DmGenPartition::test
+}
+
diff --git a/dmgen-1.0.0/src/patchwin.tcl b/dmgen-1.0.0/src/patchwin.tcl
new file mode 100644
index 0000000..d865017
--- /dev/null
+++ b/dmgen-1.0.0/src/patchwin.tcl
@@ -0,0 +1,345 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Implementation of the patch window which displays a problem-space or
+# operator and allow it to be edited by the user. This window is spawned
+# when the user chooses a ps or op from the datamap window.
+#
+# Requires:
+# bwutil.tcl
+# datamap.tcl
+# soarutil.tcl
+
+package require BWidget
+
+namespace eval PatchWin {
+ # Returns the widget path for a patch window given a ps or op handle.
+ # This will return a value, even if the window doesn't exist!
+ proc Get { h } { return .$h }
+
+ # Create a patch window for the given ps or op handle, or raise it if
+ # one already exists.
+ #
+ # @param h Handle to PS or OP, returned from Datamap:: functions.
+ # @returns Widget path of window.
+ proc Create { h } {
+ set w [Get $h]
+
+ # If there's already a window for this handle, raise it and return
+ if [winfo exists $w] {
+ raise $w
+ return $w
+ }
+ set dm [Datamap::GetDatamap $h]
+ set w [toplevel $w] ;# create toplevel window
+ #wm geometry $w 500x400
+
+ # set up a window close handler
+ bind $w [list PatchWin::onDestroy {%W} $w $h]
+
+ # set the window title
+ set dmName [Datamap::GetName $dm]
+ if [Datamap::IsProblemSpace $h] {
+ wm title $w "Datamap: $dmName, Problem Space: [Datamap::GetPsOrOpName $h]"
+ } else {
+ wm title $w "Datamap: $dmName, Operator: [Datamap::GetPsOrOpName $h]"
+ }
+
+ # Add a menubar
+ set mb [menu $w.mb]
+ $w config -menu $mb
+ $mb add command -label "Datamap" -command "raise [DmWin::Get $dm]"
+ foreach m { Edit ProblemSpaces Operators } {
+ set mnu$m [menu $mb.mnu$m]
+ $mb add cascade -label $m -menu $mb.mnu$m
+ }
+
+ # Set up post callbacks for PS and OP menus
+ $mnuProblemSpaces config -postcommand "PatchWin::psMenuPost $w $h"
+ $mnuOperators config -postcommand "PatchWin::opMenuPost $w $h"
+
+ # Create a tree on the left of the window
+ ScrolledWindow $w.sw
+ set g [Datamap::GetGraph $h]
+ set s [Datamap::GetStartVertex $h]
+ set tree [BwUtil::NewBWidgetTreeFromGraph $w.tree $g $s name]
+ $tree bindText "PatchWin::onTreeLeftClick $w $h"
+ $tree bindText "PatchWin::onTreeRightClick $w $h %X %Y"
+ $w.sw setwidget $tree
+ #ExpandBWidgetTree $tree
+
+ # Create a popup menu for right-clicking tree nodes
+ set pu [menu $tree.popup -tearoff 0]
+ menu $pu.prods
+
+
+ # Create a frame on the right with widgets for editing the selected
+ # tree node.
+ set f [frame $w.f]
+
+
+ grid [label $f.nameLbl -text "Name:"] -column 0 -row 1 -sticky e
+ grid [entry $f.name] -column 1 -row 1 -sticky ew
+
+ grid [label $f.valueLbl -text "Value(s):"] -column 0 -row 2 -sticky e
+ grid [entry $f.value] -column 1 -row 2 -stick ew
+
+ grid [label $f.typeLbl -text "Type:"] -column 0 -row 3 -sticky e
+ set cb [ComboBox $f.type -values [Production::NodeTypes] \
+ -editable false]
+ $cb setvalue @0
+ grid $cb -column 1 -row 3 -sticky ew
+
+
+ grid [label $f.commentLbl -text "Comment:"] -column 0 -row 4 -sticky e
+ grid [text $f.comment] -column 1 -row 4
+
+ set cb [checkbutton $f.showUnknownTypes \
+ -text "Mark (?) nodes with type unknown" \
+ -command "PatchWin::onUpdateAllNodes $w $h" \
+ -variable $f.showUnknownTypes]
+ grid $cb -column 1 -row 5
+ set cb [checkbutton $f.showEmptyValues \
+ -text "Mark (@) nodes with empty value" \
+ -command "PatchWin::onUpdateAllNodes $w $h" \
+ -variable $f.showEmptyValues]
+ grid $cb -column 1 -row 6
+
+ foreach v [$g GetVertices] {
+ updateNodeDisplay $w $h $g $v
+ }
+
+ pack $w.sw $tree -expand yes -fill both -side left
+
+ pack $f -side right -expand yes -fill both
+
+ return $w
+ }
+ proc psMenuPost { w h } {
+ set mnu $w.mb.mnuProblemSpaces
+ $mnu delete 0 end
+
+ # Fill the PS menu with all PSs, except for this one if it's a PS.
+ if [Datamap::IsProblemSpace $h] {
+ set name [Datamap::GetPsOrOpName $h]
+ } else {
+ set name "" ;# Just so it doesn't match below
+ }
+ set dm [Datamap::GetDatamap $h]
+ foreach ps [lsort [Datamap::GetProblemSpaces $dm]] {
+ set n [Datamap::GetPsOrOpName $ps]
+ if { [string compare $n $name] != 0 } {
+ $mnu add command -label $n \
+ -command "PatchWin::Create $ps"
+ }
+ }
+ }
+ proc opMenuPost { w h } {
+ set mnu $w.mb.mnuOperators
+ $mnu delete 0 end
+
+ # Fill the OP menu with all OPs, except for this one if it's a OP.
+ if [Datamap::IsOperator $h] {
+ set name [Datamap::GetPsOrOpName $h]
+ } else {
+ set name "" ;# Just so it won't match below
+ }
+ set dm [Datamap::GetDatamap $h]
+ foreach op [lsort [Datamap::GetOperators $dm]] {
+ set n [Datamap::GetPsOrOpName $op]
+ if { [string compare $n $name] != 0 } {
+ $mnu add command -label $n \
+ -command "PatchWin::Create $op"
+ }
+ }
+ }
+ proc onDestroy { widget w h } {
+ if { [string compare $widget $w] != 0 } {
+ return
+ }
+ ;# nothing to do here yet...
+ }
+
+ # If 'new' value of vertex field is different from the current one,
+ # patch the vertex with the new value.
+ proc patchOnChange { g v field new } {
+ set old [$g Get $v $field]
+ if { [string compare $new $old] != 0 } {
+ DmPatch::PatchVertexFast $g $v $field $new
+ return 1
+ }
+ return 0
+ }
+ proc updateNodeDisplay { w h graph node } {
+ set tree $w.tree
+ set name [$graph Get $node name]
+ array set data [$tree itemcget $node -data]
+ if { [llength [$graph Get $node link]] > 0 || \
+ [llength $data(BackEdges)] > 0 } {
+ set name "$name -->"
+ }
+ # check for unknown type
+ set type [$graph Get $node type]
+ global $w.f.showUnknownTypes
+ if { [set $w.f.showUnknownTypes] && \
+ [string compare $type "unknown"] == 0 } {
+ set name "? $name"
+ }
+ # check for empty value
+ global $w.f.showEmptyValues
+ if { [set $w.f.showEmptyValues] && \
+ [string compare $type "identifier"] != 0 && \
+ [llength [$graph Get $node value]] == 0 } {
+ set name "@ $name"
+ }
+ $tree itemconfigure $node -text $name
+ if { [llength [$graph Get $node patched]] > 0 } {
+ $tree itemconfigure $node -fill blue
+ }
+ }
+ proc onTreeLeftClick { w h node } {
+ set f $w.f
+ set g [Datamap::GetGraph $h]
+
+ set sel [$w.tree selection get]
+ if { $sel != "" } {
+ set c [expr [patchOnChange $g $sel name [$f.name get]] || \
+ [patchOnChange $g $sel value [$f.value get]] || \
+ [patchOnChange $g $sel type [BwUtil::GetComboBoxText $f.type]] || \
+ [patchOnChange $g $sel comment [split [BwUtil::GetTextBoxText $f.comment] "\n"]]]
+ if $c {
+ updateNodeDisplay $w $h $g $sel
+ }
+ }
+
+ $w.tree selection set $node
+
+ BwUtil::SetEntryText $f.name [$g Get $node name]
+ BwUtil::SetEntryText $f.value [$g Get $node value]
+ BwUtil::SetComboBoxValue $f.type [$g Get $node type]
+ BwUtil::SetTextBoxText $f.comment [join [$g Get $node comment] "\n"]
+
+ foreach p { name value type comment } {
+ $f.[join [list $p Lbl] "" ] configure -foreground black
+ }
+ foreach p [$g Get $node patched] {
+ $f.[join [list $p Lbl] "" ] configure -foreground blue
+ }
+ }
+ proc onTreeRightClick { w h x y node } {
+ onTreeLeftClick $w $h $node
+
+ set pu $w.tree.popup
+ $pu delete 0 end
+
+ set g [Datamap::GetGraph $h]
+
+ # If source productions are available, show a menu with a list of them
+ set prods [$g Get $node prods]
+ set hasProds 0
+ if { [llength $prods] > 0 } {
+ set hasProds 1
+ $pu add cascade -label "Productions" -menu $pu.prods
+ $pu.prods config \
+ -postcommand "PatchWin::onSourceProdsPost $pu.prods $h $node"
+ }
+
+ set link [$g Get $node link]
+
+ # if there are any links, add menu items to follow them
+ set hasLinks 0
+ if { [llength $link] > 0 } {
+ if { $hasProds } {
+ $pu add separator ;# separate this from source prods
+ }
+ set hasLinks 1
+ set type [lindex $link 0]
+ #set names [lindex $link 1]
+ set names [lrange $link 1 end]
+ if { $type == "S" } {
+ set typeName "Problem Space"
+ } else {
+ set typeName "Operator"
+ }
+ set dm [Datamap::GetDatamap $h]
+ foreach n $names {
+ set nh [Datamap::GetPsOrOp $dm $type $n]
+ $pu add command -label "Go to $typeName: $n" \
+ -command "PatchWin::Create $nh"
+ }
+ }
+ # If there are any backedges, we add menu items to go to those
+ # vertices from here.
+ array set data [$w.tree itemcget $node -data]
+ if { [llength $data(BackEdges)] > 0 } {
+ if { $hasLinks } {
+ $pu add seperator ;# separate this from the links
+ }
+ set hasLinks 1
+ set s [Datamap::GetStartVertex $h]
+ array set pi [Dijkstra::ShortestPaths $g Dijkstra::UnitWeight $s]
+ foreach v $data(BackEdges) {
+ set path [join [DmPatch::GetVertexPath $g $s $v pi] "." ]
+ $pu add command -label "Backedge: $path" \
+ -command "PatchWin::onTreeLeftClick $w $h $v"
+ }
+ }
+
+ if { $hasProds || $hasLinks } {
+ tk_popup $w.tree.popup $x $y
+ }
+ }
+ # Command called when the source productions submenu of a right-click is
+ # posted. Just fills in the list of productions and adds a command that
+ # prints the production to the console.
+ proc onSourceProdsPost { mnu h node } {
+ $mnu delete 0 end
+ set g [Datamap::GetGraph $h]
+ foreach p [$g Get $node prods] {
+ set cmd "SoarUtil::GetSoarPrint $p"
+ $mnu add command -label $p \
+ -command "puts \"\[$cmd\]\""
+ }
+ }
+
+ proc onUpdateAllNodes { w h } {
+ set g [Datamap::GetGraph $h]
+ foreach v [$g GetVertices] {
+ updateNodeDisplay $w $h $g $v
+ }
+ }
+}
diff --git a/dmgen-1.0.0/src/production.tcl b/dmgen-1.0.0/src/production.tcl
new file mode 100644
index 0000000..e322223
--- /dev/null
+++ b/dmgen-1.0.0/src/production.tcl
@@ -0,0 +1,527 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Code for representing productions as graphs
+#
+# A Production is represented as a graph. Each vertex has the following
+# properties:
+# name - Name of vertex (state, name, etc)
+# type - Type of vertex (identifier, string, float, etc)
+# value - Value of vertex (only meaningful for string, float, etc)
+# special -
+# isState - true if the structure under this vertex is a state
+# isVariablized - true if this vertex represents a variablized attribute
+# valRelOps - Relational ops that we're used in the test of the value
+# e.g., not_equal, less, equal, etc.
+# side - which side of the production it came from (L, R, or B).
+#
+# Requires:
+# parser.tcl
+# util.tcl
+# graph.tcl
+# soarutil.tcl
+
+namespace eval Production {
+ # Properties of each node
+ proc NodeProps {} { return {
+ name
+ type
+ value
+ special
+ isState
+ isVariablized
+ valRelOps
+ side
+ } }
+ # Property defaults values
+ proc NodePropDefaults {} { return {
+ name "unknown"
+ type unknown
+ value {}
+ special {}
+ isState 0
+ isVariablized 0
+ valRelOps {}
+ side B
+ } }
+
+ # Possible values for 'type' node property
+ # DR - removed enum 7/25/02
+ proc NodeTypes {} { return { unknown identifier string int float } }
+
+ # Possible values for 'special' node property
+ # Should ProblemSpace be removed? I'm not sure if it's ever actually
+ # used. partition.tcl appears to just use ProblemSpaceSpec.
+ proc SpecialTypes {} { return {
+ ProblemSpace
+ ProblemSpaceSpec
+ Operator
+ OperatorSpec
+ TopState
+ SuperState
+ } }
+
+ proc StateSpec {} { return state }
+
+ variable psSpec ;# internal problem-space spec list
+
+ # Use this for TAS-style (state.problem-space.name)
+ set psSpec { problem-space name }
+ # Use this for Visual Soar-style (state.name)
+ #set psSpec { name }
+
+ ##
+ # PS spec 'constant'. Set the value by calling with a single
+ # argument.
+ proc ProblemSpaceSpec { { s {} } } {
+ variable psSpec
+ if { [llength $s] > 0 } {
+ set psSpec $s
+ }
+ return $psSpec
+ }
+
+ proc OperatorSpec {} { return { operator name } }
+ proc TopStateSpec {} { return { top-state } }
+ proc SuperStateSpec {} { return { superstate } }
+
+ ##
+ # Parse a production
+ #
+ # @param name Name of production to parse
+ # @returns The graph of the production
+ proc Parse { name } {
+ set graph [parse $name]
+
+ return $graph
+ }
+
+ ##
+ # Return all nodes with isState property set to true
+ #
+ # @param graph Production graph returned by Parse
+ # @returns List of node tags
+ proc GetStates { graph } {
+ set r {}
+ foreach v [$graph GetVertices] {
+ if [$graph Get $v isState] {
+ lappend r $v
+ }
+ }
+ return $r
+ }
+
+ ##
+ # Return all nodes with 'special' attribute set to ProblemSpace
+ #
+ # @param graph Production graph
+ # @param state State node to start search at
+ # @returns List of node tags
+ proc GetProblemSpaces { graph state } {
+ set r {}
+ foreach v [$graph GetVertices] {
+ if { [$graph Get $v special] == "ProblemSpace" } {
+ lappend r $v
+ }
+ }
+ return $r
+ }
+
+ ##
+ # Return all nodes with 'special' attribute set to Operator
+ #
+ # @param graph Production graph
+ # @returns List of node tags
+ proc GetOperators { graph } {
+ set r {}
+ foreach v [$graph GetVertices] {
+ if { [$graph Get $v special] == "Operator" } {
+ lappend r $v
+ }
+ }
+ return $r
+ }
+
+ ##
+ # Parse a loaded Soar production and return its graph
+ proc parse { name } {
+ set buf [SoarUtil::GetSoarPrintInternal $name]
+ if { $buf == {} } {
+ puts "No loaded production: $name"
+ return {}
+ }
+
+ # Parse the production into WMEs
+ set wmes [parse_production $buf]
+ if {$wmes == 0} {
+ puts "Could not parse production $name"
+ puts $buf
+ return {}
+ }
+ return [buildProduction $wmes]
+ }
+
+ proc sidesAreCompatible { s0 s1 } {
+ if {$s0 == $s1 } {
+ return 1
+ } elseif { $s0 == "B" || $s1 == "B" } {
+ return 1
+ }
+ return 0
+ }
+
+ proc MergeSideValues { s0 s1 } {
+ if { $s0 != $s1 } {
+ return B
+ } else {
+ return $s0
+ }
+ }
+
+ ##
+ # Builds a production graph given the list returned b parse_production
+ #
+ # Rewritten for file version 1.9 to handle LHS/RHS asymmetry
+ #
+ # @param list of wmes { Side Id AttrName Value }
+ proc buildProduction { wmes } {
+ set wmes [lunique $wmes] ;# Remove repeats
+
+# foreach s $wmes {
+# puts $s
+# }
+
+ set graph [Graph::Create [NodeProps]]
+ array set props [NodePropDefaults]
+ set props(name) TOP
+ set props(side) L
+ # Insert a fake TOP node to start from
+ set top [$graph InsertVertex [array get props]]
+
+ set tids($top) TOP ;# maps nodes to id values (<*>)
+ set tIdToNodes(TOP) $top ;# maps ids to nodes (multi-map)
+ set tNodeReroutes($top) $top ;# lookup table rerouting node when they are
+ ;# replaced because they're a duplicate
+
+ set states {}
+ foreach s $wmes {
+ set side [lindex $s 0]
+ set id [lindex $s 1]
+ set attr [lindex $s 2]
+ set val [lindex $s 3]
+
+ set attrRelOps [lindex $s 4]
+ set valRelOps [lindex $s 5]
+
+ unset props
+ array set props [NodePropDefaults]
+ set props(name) $attr
+ set props(side) $side
+ set props(valRelOps) $valRelOps
+ set props(isVariablized) [isVariable $attr]
+ if { [string compare $attr "state"] == 0 && [string compare $id "TOP"] == 0 } {
+ set props(isState) 1
+ }
+
+ set n [$graph InsertVertex [array get props]]
+ set tNodeReroutes($n) $n ;# Add identity mapping to reroute table for now
+
+ # Accumulate list of state node for later...
+ if $props(isState) {
+ lappend states $n
+ }
+
+ # Is this a terminal node?
+ if { [isVariable $val] } then { ;# non-terminal
+ set tids($n) $val
+ if ![info exists tIdToNodes($val)] {
+ set tIdToNodes($val) {}
+ }
+ set tIdToNodes($val) [lunion $tIdToNodes($val) $n]
+ } else { ;# terminal, just store the value
+ $graph Set $n value $val
+ }
+ set tparents($n) $id
+ }
+# parray tparents
+# parray tIdToNodes
+ # Now the graph has all of its vertices. Let's go through and set
+ # parents making sure we take which side of the production the
+ # node was found on.
+ foreach n [$graph GetVertices] {
+ if ![info exists tparents($n)] { ;# no parents
+ continue
+ }
+ # We don't need to merge states, just leave them...
+ if { [string compare $tparents($n) TOP] == 0 } {
+ $graph AddEdge $top $n
+ continue
+ }
+ set side [$graph Get $n side]
+ set name [$graph Get $n name]
+
+ # Get all the nodes that match this parent id
+ if { ![info exists tIdToNodes($tparents($n))] } {
+ LogWarning "No node for parent $tparents($n), skipping"
+ continue
+ }
+ set potParents $tIdToNodes($tparents($n)) ;# potential parents
+# puts "$name - $n"
+# puts "pot = $potParents"
+ set mySideParents {} ;# parents on the same side as me
+ set otherSideParents {} ;# parents on the other side from me
+ foreach p $potParents {
+ if { $p != $n && $p < $n } { ;# prevent self-loops
+ # Which side is the potential parent on relative to me?
+ # Use the reroute table in case the parent has moved...
+ if [sidesAreCompatible $side [$graph Get $p side]] {
+ lappend mySideParents $tNodeReroutes($p)
+ } else {
+ lappend otherSideParents $tNodeReroutes($p)
+ }
+ }
+ }
+# puts "my = $mySideParents"
+# puts "other = $otherSideParents"
+ # We give priority to parents that are on the same side as
+ # the node.
+ set parentsFound 0
+ set realParents {}
+ if { [llength $mySideParents] > 0 } {
+ set realParents $mySideParents
+ set parentsFound 1
+ } elseif { [llength $otherSideParents] > 0 } {
+ set realParents $otherSideParents
+ set parentsFound 1
+ }
+ if { $parentsFound } {
+ # now reparent node under each of its true parents
+ foreach p $realParents {
+# puts "parenting under $p"
+ # Does this parent already have a child by the same name?
+ set sibs [$graph GetOutAdjacencies $p]
+ set fnode ""
+ foreach s $sibs {
+ if { [$graph Get $s name] == $name } { ;# Yes!
+ set fnode $s
+ }
+ }
+ # If there is a sibling with the same name, merge our properties
+ # in with those of the sibling and don't reparent ourself...
+ if { $fnode != "" } {
+ $graph Set $fnode value [lunion [$graph Get $fnode value] [$graph Get $n value]]
+ # Now when are children try to find their parent they'll find
+ # this replacement instead...
+ set tNodeReroutes($n) $fnode
+ # other stuff?
+ $graph Set $fnode side [MergeSideValues [$graph Get $fnode side] $side]
+ } else {
+ $graph AddEdge $p $n ;# just set the node's parent
+ }
+ }
+ } else {
+ puts "No parents found!"
+ }
+ }
+ # Find all of the nodes that were duplicates and prune them from the
+ # graph...
+ foreach n [$graph GetVertices] {
+ if { $n != $top && [llength [$graph GetInAdjacencies $n]] == 0 } {
+ $graph DeleteVertex $n
+ }
+ }
+ # Determine special field for all nodes...
+ foreach n [$graph GetVertices] {
+ set sfVisitTable($n) 0
+ }
+ foreach s $states {
+ setSpecialFields $graph $top $s {} sfVisitTable
+ }
+ # Try to guess types of all vertices...
+ $graph Map Production::setTypeField
+
+ return $graph
+ }
+
+ ##
+ # Determine any special attributes of a node such as problem-space, state,
+ # operator, etc.
+ #
+ # @param g The graph
+ # @param parents List of parents of this node
+ # @param n The node
+ # @param path The node name path (list of names)
+ # @param visitTableName A hashtable to indicate when a node has already
+ # been visited.
+ proc setSpecialFields { g parents n path visitTableName } {
+ upvar $visitTableName visitedTable
+ set visitedTable($n) 1 ;# mark this node as visited
+ set name [$g Get $n name]
+ set parent [lindex $parents end]
+ set nParents [llength $parents]
+ set p [concat $path $name]
+ set notfound 1
+
+ # This mess is mostly to handle finding problem-spaces no matter how
+ # they're specified in the productions (e.g. ^problem-space.name for TAS,
+ # ^name for Visual Soar code, etc). The code below for OperatorSpec et al
+ # should also look like this, but ^operator.name is more consistent so
+ # we'll worry about that when the time comes...
+
+ # Let's see if we've found a problems space specifier
+ # (e.g. ^problem-space.name)
+ set psSpec [ProblemSpaceSpec] ;# The spec
+ set psSpecLen [llength $psSpec] ;# length of spec
+ # Does the current path look like the spec?
+ if { [lcompare [ltail $p $psSpecLen] $psSpec] } {
+ # ok, is the parent of the top of the spec a state?
+ # i.e., we have to have state.problem-space.name or
+ # superstate.problem-space.name. This is crucial if the spec is just
+ # ^name as in the case of visual soar generated code.
+ set specParent [lindex $parents [expr $nParents - $psSpecLen]]
+ if [$g Get $specParent isState] {
+ $g Set $n special ProblemSpaceSpec
+ $g Set $parent special ProblemSpace
+ set notfound 0
+ }
+ }
+
+ if { $notfound && [lcompare [ltail $p [llength [OperatorSpec]]] [OperatorSpec]] } {
+ $g Set $n special OperatorSpec
+ $g Set $parent special Operator
+ } elseif { [lcompare [ltail $p [llength [TopStateSpec]]] [TopStateSpec]] } {
+ $g Set $n special TopState
+ $g Set $n isState 1
+ } elseif { [lcompare [ltail $p [llength [SuperStateSpec]]] [SuperStateSpec]] } {
+ $g Set $n special SuperState
+ $g Set $n isState 1
+ }
+
+ # depth first left-to-right traversal
+ foreach c [$g GetOutAdjacencies $n] {
+ if { !$visitedTable($c) } {
+ setSpecialFields $g [concat $parents $n] $c $p visitedTable
+ }
+ }
+ }
+
+ ##
+ # Is the string in 'val' a Soar variable, i.e. <*>
+ proc isVariable { val } {
+ return [string match <*> $val]
+ }
+ ##
+ # Get list of variables from 'list'
+ proc getVarList { list } {
+ set olist {}
+ foreach v $list {
+ if [isVariable $v] {
+ lappend olist $v
+ }
+ }
+ return $olist
+ }
+ ##
+ # Get list of non-variables from 'list'
+ proc getValueList { list } {
+ set olist {}
+ foreach v $list {
+ if ![isVariable $v] {
+ lappend olist $v
+ }
+ }
+ return $olist
+ }
+
+ proc extractAttrName { s } {
+ set e [expr [string last "," $s] + 1]
+ return [string range $s $e end]
+ }
+ proc extractVarName { s } {
+ set e [expr [string first "," $s] - 1]
+ return [string range $s 0 $e]
+ }
+ ##
+ # Tries to guess the type of a node.
+ proc setTypeField { graph v } {
+ set name [$graph Get $v name]
+
+ if [llength [$graph GetOutAdjacencies $v]] {
+ $graph Set $v type identifier
+ return
+ }
+ set val [$graph Get $v value]
+ set len [llength $val]
+ if { $len == 0 } {
+ $graph Set $v type unknown
+ } else {
+ $graph Set $v type [SoarUtil::GuessSoarTypeFromList $val]
+ }
+ }
+
+} ;# namespace Production
+
+IfStandAlone { ;# Some test code
+ lappend auto_path $env(SOAR_LIBRARY)
+ package require Soar
+
+ sp {test0
+ (state ^operator
+ ^problem-space.name jim
+ ^judy )
+ ( ^name bob)
+ (state ^operator
+ ^problem-space.name jim2)
+ ( ^name bob2)
+ ( ^{ << var1 var2 var3 >> } )
+ -->
+ (write (crlf) |Judy message from | )
+ }
+
+ set g [Production::Parse test0]
+ set t [$g FindVertex name TOP]
+ $g MapBreadthFirst $t Graph::Print
+
+ set states [Production::GetStates $g]
+ puts "States = $states"
+ foreach s $states {
+ puts "state $s"
+ puts " ProblemSpaces = [Production::GetProblemSpaces $g $s]"
+ puts " Operators = [Production::GetOperators $g $s]"
+ }
+
+} ;# End test code
diff --git a/dmgen-1.0.0/src/soarutil.tcl b/dmgen-1.0.0/src/soarutil.tcl
new file mode 100644
index 0000000..05e8fa8
--- /dev/null
+++ b/dmgen-1.0.0/src/soarutil.tcl
@@ -0,0 +1,190 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Various utility functions for dealing with Soar.
+#
+# Requires:
+# Soar
+# production.tcl (Production::NodeTypes)
+
+namespace eval SoarUtil {
+
+##
+# Strip the bars off a Soar string if they're both there.
+#
+# @param s The String to process
+# @returns If s has bars, returns s with the bars removed. Otherwise,
+# returns s
+proc StripSoarBars { s } {
+ set n [string length $s]
+ if { $n > 1 && \
+ [string range $s 0 0 ] == "|" && \
+ [string range $s end end ] == "|" } {
+ return [string range $s 1 [expr $n - 2]]
+ }
+ return $s
+}
+
+##
+# Run a soar command and return its output.
+#
+# @param cmd Command to run
+# @returns Result of command
+proc RunSoarCommand { cmd } {
+ output-strings-destination -push -append-to-result
+ catch {
+ set buf [eval $cmd]
+ }
+ output-strings-destination -pop
+ return $buf
+}
+
+##
+# Get the result of "print -internal" for the specified production
+#
+# @param name Name of production
+# @returns {} if an error occured, the results otherwise.
+proc GetSoarPrintInternal { name } {
+ set buf [RunSoarCommand "print -internal $name"]
+ if { [string range $buf 0 1] != "sp" } {
+ return {}
+ }
+ return $buf
+}
+
+##
+# Get the result of "print" for the specified production
+#
+# @param name Name of production
+# @returns {} if an error occured, the results otherwise.
+proc GetSoarPrint { name } {
+ set buf [RunSoarCommand "print $name"]
+ if { [string range $buf 0 1] != "sp" } {
+ return {}
+ }
+ return $buf
+}
+
+##
+# Get a list of all loaded productions
+proc GetSoarProductions { } {
+ set L {}
+ set b [split [RunSoarCommand "print -all"] " \n"]
+ foreach p $b {
+ if { [llength $p] > 0 } {
+ lappend L [StripSoarBars $p]
+ }
+ }
+ return $L
+}
+
+##
+# Get the name of the file from which a production was loaded.
+#
+# @param name Name of production
+# @returns Name of file.
+proc GetSoarProductionFile { name } {
+ return [RunSoarCommand "print -filename $name"]
+}
+
+##
+# Try to guess the type of a single value (int, float, or string)
+#
+proc GuessSoarType { s } {
+ set t {}
+ set s [string trim $s]
+ set int {^([+-])*[0-9]+$}
+ set float1 {^([+-])*[0-9]*\.?[0-9]+$} ;# normal float
+ set float2 {^([+-])*[0-9]+\.$} ;# no digits after '.'
+ if [regexp $int $s] {
+ set t int
+ } elseif [regexp $float1 $s] {
+ set t float
+ } elseif [regexp $float2 $s] {
+ set t float
+ } else {
+ set t string
+ }
+ return $t
+}
+
+##
+# Try to guess a Soar type given a list of values...
+proc GuessSoarTypeFromList { s } {
+ set ls [llength $s]
+ if { $ls == 0 } { ;# no value, no guess (could be identifier?)
+ return unknown
+ }
+ if { $ls == 1 } { ;#single value, one guess
+ return [GuessSoarType $s]
+ }
+
+ # initialize bitmap indexed by typename
+ foreach i [Production::NodeTypes] { set rlu($i) 0 }
+
+ # accumulate individual guesses in a bitmap indexed by typename
+ set lr 0 ;# count of number of different guesses encountered
+ foreach v $s {
+ set t [GuessSoarType $v]
+ if { $rlu($t) == 0 } { incr lr }
+ set rlu($t) 1
+ }
+
+ if { $lr == 1 } { ;# single type guessed. yay.
+ if { $rlu(float) } {
+ set r float
+ } elseif { $rlu(int) } {
+ set r int
+ } else {
+ #set r enum
+ set r string
+ }
+ } elseif { $lr > 0 } { ;# multiple, conflicting guesses
+ # possibilities are string int float...
+
+ # If only float and int have been guessed, go with float.
+ if { $lr == 2 && $rlu(float) && $rlu(int) } {
+ set r float
+ } else { ;# mix of strings, ints, and floats, go with enum
+ #set r enum
+ set r string
+ }
+ }
+ return $r
+}
+
+} ;# end namespace SoarUtil
diff --git a/dmgen-1.0.0/src/tclIndex b/dmgen-1.0.0/src/tclIndex
new file mode 100644
index 0000000..2db94e1
--- /dev/null
+++ b/dmgen-1.0.0/src/tclIndex
@@ -0,0 +1,228 @@
+# Tcl autoload index file, version 2.0
+
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Only "public" functions from each module are included in the auto index.
+# Public procs are easy to find because they start with a capital letter,
+# with the exception of util.tcl, lexer.tcl and parser.tcl
+
+##
+# Set a flag so we know where we're coming from...
+global DmGenAutoLoaded
+set DmGenAutoLoaded 1
+
+##
+# These are for an overly complicated and painful "compiled"
+# version of dmgen. For now, we'll hard code the DmGenCompiled
+# flag to 0 to avoid any weird behavior or bugs... DR 10/22/2003
+global DmGenCompiled
+set DmGenCompiled 0
+global DmGenTbcVersion
+
+global tcl_version
+
+if { $DmGenCompiled } {
+ set ext tbc
+ array set verdirtab { 8.0 10 \
+ 8.3 13 }
+ if { [info exists verdirtab($tcl_version)] } {
+ set DmGenTbcVersion $verdirtab($tcl_version)
+ set dir [file join $dir "tbc$DmGenTbcVersion"]
+ } else {
+ puts stderr "Unsupported Tcl version: $tcl_version"
+ exit 1
+ }
+} else {
+ set ext tcl
+ set verdir ""
+}
+
+
+
+set auto_index(::DmGenCfg::Read) [list source [file join $dir config.$ext]]
+set auto_index(::DmGenCfg::Write) [list source [file join $dir config.$ext]]
+set auto_index(::DmGenCfg::Get) [list source [file join $dir config.$ext]]
+set auto_index(::DmGenCfg::Set) [list source [file join $dir config.$ext]]
+
+set auto_index(::BwUtil::ExpandBWidgetTree) [list source [file join $dir bwutil.$ext]]
+set auto_index(::BwUtil::NewBWidgetTreeFromGraph) [list source [file join $dir bwutil.$ext]]
+set auto_index(::BwUtil::GetComboBoxText) [list source [file join $dir bwutil.$ext]]
+set auto_index(::BwUtil::SetComboBoxValue) [list source [file join $dir bwutil.$ext]]
+set auto_index(::BwUtil::SetEntryText) [list source [file join $dir bwutil.$ext]]
+set auto_index(::BwUtil::GetTextBoxText) [list source [file join $dir bwutil.$ext]]
+set auto_index(::BwUtil::SetTextBoxText) [list source [file join $dir bwutil.$ext]]
+set auto_index(::Datamap::VertexFields) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::DefVertexFields) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::Create) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::Clear) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::Destroy) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetName) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::CreateProblemSpace) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::FindOrCreateProblemSpace) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::CreateOperator) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::FindOrCreateOperator) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::RemoveProblemSpace) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::RemoveOperator) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetProblemSpaces) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetOperators) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::Generate) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetPsOrOp) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetProblemSpace) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetOperator) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetDatamap) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetPsOrOpName) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetType) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::IsProblemSpace) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::IsOperator) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetGraph) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::GetStartVertex) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::FindVertexFromPath) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::DefAttrSortPriority) [list source [file join $dir datamap.$ext]]
+set auto_index(::Datamap::SortAttributes) [list source [file join $dir datamap.$ext]]
+set auto_index(::Dijkstra::Inf) [list source [file join $dir dijkstra.$ext]]
+set auto_index(::Dijkstra::ShortestPaths) [list source [file join $dir dijkstra.$ext]]
+set auto_index(::Dijkstra::UnitWeight) [list source [file join $dir dijkstra.$ext]]
+set auto_index(GenerateDatamap) [list source [file join $dir dmgen.$ext]]
+set auto_index(::DmPatch::PatchVertex) [list source [file join $dir dmpatch.$ext]]
+set auto_index(::DmPatch::PatchVertexFast) [list source [file join $dir dmpatch.$ext]]
+set auto_index(::DmPatch::RemoveVertex) [list source [file join $dir dmpatch.$ext]]
+set auto_index(::DmPatch::SavePatches) [list source [file join $dir dmpatch.$ext]]
+set auto_index(::DmPatch::writePatch) [list source [file join $dir dmpatch.$ext]]
+set auto_index(::DmPatch::ApplyPatchFile) [list source [file join $dir dmpatch.$ext]]
+set auto_index(::DmPatch::GetVertexPath) [list source [file join $dir dmpatch.$ext]]
+set auto_index(::DmWin::Get) [list source [file join $dir dmwin.$ext]]
+set auto_index(::DmWin::Create) [list source [file join $dir dmwin.$ext]]
+set auto_index(::Graph::NullVertex) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Create) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Destroy) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Copy) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::InsertVertex) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::AddEdge) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::RemoveEdge) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Set) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::SetL) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::SetAll) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Get) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::DeleteVertex) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::GetFields) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::GetVertices) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::EdgeExists) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::GetOutAdjacencies) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::GetInAdjacencies) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Map) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::MapDepthFirst) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::MapBreadthFirst) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::MapOutAdjacencies) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::MapInAdjacencies) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::IsEmpty) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Size) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::FindVertex) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::BasicVertexCopy) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::Print) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::SortVertListByField) [list source [file join $dir graph.$ext]]
+set auto_index(::Graph::SortOutAjacencies) [list source [file join $dir graph.$ext]]
+set auto_index(::DmGenHtmlOut::EscapeHtmlString) [list source [file join $dir htmlout.$ext]]
+set auto_index(::DmGenHtmlOut::WriteHtmlDatamap) [list source [file join $dir htmlout.$ext]]
+set auto_index(get_lexeme) [list source [file join $dir lexer.$ext]]
+
+set auto_index(LogError) [list source [file join $dir log.$ext]]
+set auto_index(LogWarning) [list source [file join $dir log.$ext]]
+set auto_index(LogInfo) [list source [file join $dir log.$ext]]
+set auto_index(Log) [list source [file join $dir log.$ext]]
+set auto_index(LogFlush) [list source [file join $dir log.$ext]]
+set auto_index(LogReset) [list source [file join $dir log.$ext]]
+set auto_index(LogSetAutoFlush) [list source [file join $dir log.$ext]]
+set auto_index(LogSetFileName) [list source [file join $dir log.$ext]]
+
+set auto_index(ProcessProd) [list source [file join $dir merge.$ext]]
+set auto_index(MergeProdIntoDatamap) [list source [file join $dir merge.$ext]]
+set auto_index(mergeProdIntoDatamap) [list source [file join $dir merge.$ext]]
+set auto_index(parse_production) [list source [file join $dir parser.$ext]]
+set auto_index(::Partition::GetPsNames) [list source [file join $dir partition.$ext]]
+set auto_index(::Partition::GetOpNames) [list source [file join $dir partition.$ext]]
+set auto_index(::Partition::PartitionProduction) [list source [file join $dir partition.$ext]]
+set auto_index(::PatchWin::Get) [list source [file join $dir patchwin.$ext]]
+set auto_index(::PatchWin::Create) [list source [file join $dir patchwin.$ext]]
+set auto_index(::Production::NodeProps) [list source [file join $dir production.$ext]]
+set auto_index(::Production::NodePropDefaults) [list source [file join $dir production.$ext]]
+set auto_index(::Production::NodeTypes) [list source [file join $dir production.$ext]]
+set auto_index(::Production::SpecialTypes) [list source [file join $dir production.$ext]]
+set auto_index(::Production::StateSpec) [list source [file join $dir production.$ext]]
+set auto_index(::Production::ProblemSpaceSpec) [list source [file join $dir production.$ext]]
+set auto_index(::Production::OperatorSpec) [list source [file join $dir production.$ext]]
+set auto_index(::Production::TopStateSpec) [list source [file join $dir production.$ext]]
+set auto_index(::Production::SuperStateSpec) [list source [file join $dir production.$ext]]
+set auto_index(::Production::Parse) [list source [file join $dir production.$ext]]
+set auto_index(::Production::GetStates) [list source [file join $dir production.$ext]]
+set auto_index(::Production::GetProblemSpaces) [list source [file join $dir production.$ext]]
+set auto_index(::Production::GetOperators) [list source [file join $dir production.$ext]]
+set auto_index(::Production::sidesAreCompatible) [list source [file join $dir production.$ext]]
+set auto_index(::Production::MergeSideValues) [list source [file join $dir production.$ext]]
+set auto_index(::SoarUtil::RunSoarCommand) [list source [file join $dir soarutil.$ext]]
+set auto_index(::SoarUtil::GetSoarPrintInternal) [list source [file join $dir soarutil.$ext]]
+set auto_index(::SoarUtil::GetSoarPrint) [list source [file join $dir soarutil.$ext]]
+set auto_index(::SoarUtil::GetSoarProductions) [list source [file join $dir soarutil.$ext]]
+set auto_index(::SoarUtil::GetSoarProductionFile) [list source [file join $dir soarutil.$ext]]
+set auto_index(::SoarUtil::GuessSoarType) [list source [file join $dir soarutil.$ext]]
+set auto_index(::SoarUtil::GuessSoarTypeFromList) [list source [file join $dir soarutil.$ext]]
+set auto_index(Constant) [list source [file join $dir util.$ext]]
+set auto_index(Static) [list source [file join $dir util.$ext]]
+set auto_index(Assert) [list source [file join $dir util.$ext]]
+set auto_index(IfStandAlone) [list source [file join $dir util.$ext]]
+set auto_index(Max) [list source [file join $dir util.$ext]]
+set auto_index(Min) [list source [file join $dir util.$ext]]
+set auto_index(GetTag) [list source [file join $dir util.$ext]]
+set auto_index(lempty) [list source [file join $dir util.$ext]]
+set auto_index(ldelete) [list source [file join $dir util.$ext]]
+set auto_index(lunique) [list source [file join $dir util.$ext]]
+set auto_index(lcompare) [list source [file join $dir util.$ext]]
+set auto_index(ltail) [list source [file join $dir util.$ext]]
+set auto_index(lunion) [list source [file join $dir util.$ext]]
+set auto_index(lintersect) [list source [file join $dir util.$ext]]
+set auto_index(ldiff) [list source [file join $dir util.$ext]]
+set auto_index(PrintTabs) [list source [file join $dir util.$ext]]
+set auto_index(UnwindDirStack) [list source [file join $dir util.$ext]]
+set auto_index(ReplaceChar) [list source [file join $dir util.$ext]]
+set auto_index(::DmGenXmlOut::EscapeXmlString) [list source [file join $dir xmlout.$ext]]
+set auto_index(::DmGenXmlOut::OpenXmlTag) [list source [file join $dir xmlout.$ext]]
+set auto_index(::DmGenXmlOut::CloseXmlTag) [list source [file join $dir xmlout.$ext]]
+set auto_index(::DmGenXmlOut::XmlTabs) [list source [file join $dir xmlout.$ext]]
+set auto_index(::DmGenXmlOut::getPsOrOpHref) [list source [file join $dir xmlout.$ext]]
+set auto_index(::DmGenXmlOut::WriteXmlDatamap) [list source [file join $dir xmlout.$ext]]
+set auto_index(::DmGenXmlOut::WriteXmlPsOrOp) [list source [file join $dir xmlout.$ext]]
+set auto_index(::DmGenXmlOut::writeXmlDatamap_r) [list source [file join $dir xmlout.$ext]]
diff --git a/dmgen-1.0.0/src/util.tcl b/dmgen-1.0.0/src/util.tcl
new file mode 100644
index 0000000..33ff4c2
--- /dev/null
+++ b/dmgen-1.0.0/src/util.tcl
@@ -0,0 +1,285 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Generic utility functions
+
+##
+# Create a globally accessible constant, e.g.
+# Constant Pi 3.1415926535
+# puts "Pi = [pi]"
+#
+# @param name Name of constant
+# @param value Value of constant
+proc Constant { name value } {
+ proc $name { } [list return $value]
+}
+
+##
+# Create a proc static variable
+# @param List of names of static variables to create
+proc Static { args } {
+ set procName [lindex [info level -1] 0]
+ foreach varName $args {
+ uplevel 1 "upvar #0 staticvars($procName:$varName) $varName"
+ }
+}
+
+##
+# Simple assertion. remove with 'proc Assert {x} { }'
+proc Assert {condition} {
+ if {[catch {uplevel [list expr $condition]} n] || $n == "" || $n == 0} {
+ puts "Assertion failed (result $n), in:"
+ set prefix ""
+ for {set i [info level]} {$i} {incr i -1} {
+ append prefix " "
+ puts "$prefix'[info level $i]'"
+ }
+ # try to call a failure handler to collect more info
+ if {![catch ::AssertionFailureHandler msg] && $msg != ""} {
+ append condition " ($msg)"
+ }
+ #error "Assertion failed: $condition"
+ puts "Assertion failed: $condition"
+ exit
+ }
+}
+
+##
+# Add code that is run if the source file is run standalone.
+#
+# @param body Code to execute when script is run standalone.
+proc IfStandAlone body {
+ global argv0
+ # If the script file is the same as "this" file, run body.
+ if { [info exists argv0] && \
+ ![string compare [file tail [info script]] [file tail $argv0]] } {
+ catch {console show}
+ uplevel $body
+ }
+ }
+
+proc Max {a args} {foreach i $args {if {$i>$a} {set a $i}};return $a}
+proc Min {a args} {foreach i $args {if {$i<$a} {set a $i}};return $a}
+
+
+##
+# Generate a unique "tag" for a particular namespace. Subsequent calls with
+# the same namespace will return new unique tags.
+#
+# @param nspace Name of tag
+# @param int If true, then the tag is simply an integer, otherwise it is a
+# string.
+proc GetTag { nspace { int 0 } } {
+ set idx __nextNum$nspace ;# A global "static" variable with the next tag
+ global $idx
+ if ![info exists $idx] { ;# initialize on first call
+ set $idx 0
+ }
+ incr $idx
+ if { $int } {
+ return [set $idx]
+ }
+ return "__tag$nspace[set $idx]"
+}
+
+##
+# Join a list of path elements with the system path separator.
+#
+# @param pathList List of path elements
+proc JoinPathList { pathList } {
+ set r ""
+ foreach p $pathList {
+ set r [file join $r $p]
+ }
+ return $r
+}
+
+##
+# Get an absolute path to the currently running script.
+#
+# This function is only accurate if it's called from a top-level
+# script that hasn't changed the current directory.
+#
+# @returns a tuple (path to script, name of script)
+proc GetPathToScript { } {
+ set relPath [info script]
+ set scriptName [file tail $relPath]
+ set dirName [file dirname $relPath]
+
+ set pathType [file pathtype $dirName]
+ if { $pathType == "absolute" } {
+ return [list $dirName $scriptName]
+ } elseif { $pathType == "relative" } {
+ set cur [file split [pwd]]
+ set parts [file split $dirName]
+ set end [llength $cur]
+ for { set i 0 } { $i < [llength $parts] } { incr i } {
+ set p [lindex $parts $i]
+ if { $p == ".." } {
+ incr end -1
+ } elseif { $p != "." } {
+ break
+ }
+ }
+ set full [concat [lrange $cur 0 [expr $end - 1]] \
+ [lrange $parts $i end]]
+ return [list [JoinPathList $full] $scriptName]
+ } else { ;# volumerelative
+ return [list $dirName $scriptName]
+ }
+}
+
+##
+# Returns true if a list is empty
+proc lempty { list } {
+ return [expr [llength $list] == 0]
+}
+
+##
+# Returns a new list that is 'list' with the first instance of 'value'
+# removed.
+#
+# @param list Input list
+# @param value Value of item to remove from list
+# @retursn New list
+proc ldelete { list value } {
+ set ix [lsearch -exact $list $value]
+ if { $ix >= 0 } {
+ return [lreplace $list $ix $ix]
+ } else {
+ return $list
+ }
+}
+
+##
+# Remove duplicates from a list and return a new list
+#
+# @param list List to process
+# @returns Copy of list with duplicates removed
+proc lunique {list} {
+ # ulist is the uniq-ed list
+ set ulist {}
+
+ # The main loop
+ foreach e $list {
+ if {![info exist vec($e)]} {
+ set vec($e) {}
+ lappend ulist $e
+ }
+ }
+
+ return [lrange $ulist 0 end]
+}
+
+proc lcompare {a b} {
+ set la [llength $a]
+ set lb [llength $b]
+
+ if { $la != $lb } { return 0 }
+ for { set i 0 } { $i < $la } { incr i } {
+ if { [lindex $a $i] != [lindex $b $i] } {
+ return 0
+ }
+ }
+ return 1
+}
+proc ltail { L i } {
+ set l [llength $L]
+ if { $l < $i } {
+ return $L
+ }
+ return [lrange $L [expr $l - $i] end]
+}
+
+##
+# Create the union of two lists, i.e. all elements from both with no duplicates
+#
+# @param a First list
+# @param b Second list
+# @returns A new list that is the a U b.
+proc lunion { a b } {
+ return [lunique [concat $a $b]]
+}
+##
+# Calculate set intersection of lists a and b and return it.
+proc lintersect { a b } {
+ set i {}
+ foreach v $a {
+ if { [lsearch -exact $b $v] >= 0 } {
+ lappend i $v
+ }
+ }
+ return $i
+}
+##
+# Calculate the set difference a - b of lists a and b and return it
+proc ldiff { a b } {
+ set d $a
+ foreach v $b {
+ set d [ldelete $d $v]
+ }
+ return $d
+}
+
+##
+# Repeatedly print a string to the console.
+#
+# @param lvl Number of repititions of string
+# @param s String to repeat
+proc PrintTabs { lvl { s " " } } {
+ for { set i 0 } { $i < $lvl } { incr i } {
+ puts -nonewline $s
+ }
+}
+
+proc UnwindDirStack {} {
+ while { ![catch { popd }] } { }
+}
+
+proc ReplaceChar { s ic oc } {
+ set l [string length $s]
+ set r ""
+ for { set i 0 } { $i != $l } { incr i } {
+ set c [string index $s $i]
+ if { [string compare $c $ic] == 0 } {
+ set c $oc
+ }
+ set r [concat $r $c]
+ }
+ return [join $r ""]
+}
+
diff --git a/dmgen-1.0.0/src/xmlout.tcl b/dmgen-1.0.0/src/xmlout.tcl
new file mode 100644
index 0000000..32b94b8
--- /dev/null
+++ b/dmgen-1.0.0/src/xmlout.tcl
@@ -0,0 +1,200 @@
+###
+# Copyright 1995-2004 Soar Technology, Inc., University of Michigan. All
+# rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SOAR
+# CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# The views and conclusions contained in the software and documentation
+# are those of the authors and should not be interpreted as representing
+# official policies, either expressed or implied, of Soar Technology, Inc.,
+# the University of Michigan, or the Soar consortium.
+###
+
+##
+# Code to write a datamap in XML
+
+namespace eval DmGenXmlOut {
+
+# a simple hack to write out a string in XML with proper escapes
+proc EscapeXmlString { s } {
+ set s [join [split $s "<"] "<"]
+ set s [join [split $s ">"] ">"]
+
+ return $s
+}
+
+proc OpenXmlTag { fd tag attrs } {
+ puts -nonewline $fd "<$tag "
+ foreach { a v } $attrs {
+ puts -nonewline $fd "$a=\"$v\" "
+ }
+ puts -nonewline $fd ">"
+}
+proc CloseXmlTag { fd tag } {
+ puts $fd "$tag>"
+}
+
+proc XmlTabs { fd lvl { s " " } } {
+ for { set i 0 } { $i < $lvl } { incr i } {
+ puts -nonewline $fd $s
+ }
+}
+
+proc getPsOrOpHref { type name } {
+ return "$type-$name.xml"
+}
+
+proc writeXmlHeader { fd } {
+ global dmGenVersion
+ puts $fd "\n"
+ puts $fd ""
+}
+
+proc WriteXmlDatamap { fn dm } {
+ pushd $fn
+
+ set pss [lsort [Datamap::GetProblemSpaces $dm]]
+ set ops [lsort [Datamap::GetOperators $dm]]
+
+ set dmfd [open index.xml w]
+ writeXmlHeader $dmfd
+ puts $dmfd ""
+ foreach h [concat $pss $ops] {
+ set name [Datamap::GetPsOrOpName $h]
+ if [Datamap::IsProblemSpace $h] {
+ set type S
+ } else {
+ set type O
+ }
+ set href [getPsOrOpHref $type $name]
+ XmlTabs $dmfd 1
+ puts $dmfd "<$type name=\"$name\" href=\"$href\"/>"
+ set hfd [open $href w]
+ writeXmlHeader $hfd
+ WriteXmlPsOrOp $hfd $h 0
+ close $hfd
+ }
+ puts $dmfd ""
+
+ close $dmfd
+
+ popd ;# pop back to original directory
+}
+
+proc WriteXmlPsOrOp { fd h depth } {
+ global XmlVisited
+ if [info exists XmlVisited] {
+ unset XmlVisited
+ }
+ if [info exists XmlRefPaths] {
+ unset XmlRefPaths
+ }
+ set graph [Datamap::GetGraph $h]
+ set name [Datamap::GetPsOrOpName $h]
+ if [Datamap::IsProblemSpace $h] {
+ set typeName "Problem Space"
+ set type S
+ } else {
+ set typeName "Operator"
+ set type O
+ }
+
+ foreach v [$graph GetVertices] {
+ set XmlVisited($v) 0
+ }
+ XmlTabs $fd $depth
+ puts $fd "<$type name=\"[Datamap::GetPsOrOpName $h]\">"
+ writeXmlDatamap_r $fd $graph [Datamap::GetStartVertex $h] [expr $depth + 1] {}
+ XmlTabs $fd $depth
+ puts $fd "$type>"
+}
+
+proc writeXmlDatamap_r { fd graph vert depth path } {
+ global XmlVisited XmlRefPaths
+ set XmlVisited($vert) 1
+
+ set out [$graph GetOutAdjacencies $vert]
+
+ array set props [$graph Get $vert]
+
+ set path [concat $path $props(name)]
+ set XmlRefPaths($vert) $path
+
+ XmlTabs $fd $depth
+# puts $fd ""
+ puts $fd ""
+ set nextDepth [expr $depth + 1]
+
+ XmlTabs $fd $nextDepth
+ puts $fd "[EscapeXmlString $props(name)]"
+
+ XmlTabs $fd $nextDepth
+ puts $fd ""
+ set valDepth [expr $nextDepth + 1]
+ foreach val $props(value) {
+ XmlTabs $fd $valDepth
+ puts $fd "[EscapeXmlString $val]"
+ }
+ XmlTabs $fd $nextDepth
+ puts $fd ""
+
+ if { $props(link) != {} } {
+ set link $props(link)
+ set type [lindex $link 0]
+ set names [lrange $link 1 end]
+ foreach n $names {
+ XmlTabs $fd $nextDepth
+ puts $fd ""
+ }
+ }
+ XmlTabs $fd $nextDepth
+ puts $fd ""
+ set prodDepth [expr $nextDepth + 1]
+ foreach p $props(prods) {
+ XmlTabs $fd $prodDepth
+ puts $fd "[EscapeXmlString $p]"
+ }
+ XmlTabs $fd $nextDepth
+ puts $fd ""
+
+ foreach v $out {
+ set name [$graph Get $v name]
+ if { !$XmlVisited($v) } { ;# we haven't hit this vertex yet
+ writeXmlDatamap_r $fd $graph $v $nextDepth $path
+ } else {
+ XmlTabs $fd $nextDepth
+ set vpath [join $XmlRefPaths($v) "."]
+# puts $fd "[EscapeXmlString $vpath]"
+ puts $fd "[EscapeXmlString $vpath]"
+ }
+ }
+ XmlTabs $fd $depth
+ puts $fd ""
+}
+
+} ;# namespace eval DmgenXmlOut
diff --git a/eaters-3.0.8/INSTALL.txt b/eaters-3.0.8/INSTALL.txt
new file mode 100644
index 0000000..7dbc93b
--- /dev/null
+++ b/eaters-3.0.8/INSTALL.txt
@@ -0,0 +1,37 @@
+$Id: INSTALL.txt,v 1.3 2004/07/10 04:46:31 toolshed Exp $
+_______________________
+Installing Eaters-3.0.8
+-----------------------
+
+Eaters 3.0.8 is part of the Soar-Suite package and is installed as a component of
+that package. Installation instructions for Soar-Suite are located in the INSTALL
+file in the soar-8.5.2 directory of the Soar-Suite package and on the Soar
+website:
+
+ http://sitemaker.umich.edu/soar/
+
+________________________________
+Running Eaters-3.0.8 on Windows:
+--------------------------------
+
+Simply double-click the start-eaters.bat file.
+
+This .bat file will run init-eaters.tcl using the version of Tcl/Tk distributed
+with Soar-Suite 8.5.2.
+
+_____________________________
+Running Eaters-3.0.8 on Unix:
+-----------------------------
+
+On Unix, type this command to run Eaters:
+./init-eaters.tcl
+
+You may need to make the same changes to the first line of the init-eaters.tcl
+file that you made to the init-soar.tcl file to point to the location of the
+wish binary on your machine. For example, if you needed to install ActiveTcl
+when you installed Soar, you would change that first line to:
+#!/usr/local/ActiveTcl/bin/wish
+
+
+--
+Updated for the Eaters 3.0.8 release by Jonathan Voigt (voigtjr@gmail.com).
diff --git a/eaters-3.0.8/LICENSE.txt b/eaters-3.0.8/LICENSE.txt
new file mode 100644
index 0000000..6d648e4
--- /dev/null
+++ b/eaters-3.0.8/LICENSE.txt
@@ -0,0 +1,30 @@
+$Id: LICENSE.txt,v 1.1 2004/07/09 23:24:29 toolshed Exp $
+
+Copyright 1995-2004 Carnegie Mellon University, University of Michigan,
+University of Southern California/Information Sciences Institute. All rights
+reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE SOAR CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained
+in the software and documentation are those of the authors and should not be
+interpreted as representing official policies, either expressed or implied, of
+Carnegie Mellon University, the University of Michigan, the University of
+Southern California/Information Sciences Institute, or the Soar consortium.
\ No newline at end of file
diff --git a/eaters-3.0.8/README.txt b/eaters-3.0.8/README.txt
new file mode 100644
index 0000000..fdc7103
--- /dev/null
+++ b/eaters-3.0.8/README.txt
@@ -0,0 +1,23 @@
+$Id: README.txt,v 1.3 2004/07/10 04:53:10 toolshed Exp $
+
+Eaters 3.0.8 is an example environment for the Soar architecture and is used for
+research and to help teach the basics of Soar in the Soar tutorial. Eaters
+3.0.8 is installed as a component of the Soar-Suite package. For more
+information, please see the website:
+
+ http://sitemaker.umich.edu/soar/
+
+____________________
+File/Directory list:
+--------------------
+README.txt - This file.
+INSTALL.txt - Installation and execution notes.
+LICENSE.txt - The license that Eaters is distributed under.
+start-eaters.bat - The Windows file used to start Eaters (see INSTALL file).
+init-eaters.tcl - The Tcl/Tk initialization code for Eaters (see INSTALL file).
+agents/ - Example and tutorial Soar agents.
+simulator/ - The Eaters Tcl/Tk source code.
+
+--
+
+Updated for the Eaters 3.0.8 release by Jonathan Voigt (voigtjr@gmail.com).
diff --git a/eaters-3.0.8/agents/counter example/counter.soar b/eaters-3.0.8/agents/counter example/counter.soar
new file mode 100644
index 0000000..53fa7f1
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter.soar
@@ -0,0 +1,3 @@
+pushd counter
+source counter_source.soar
+popd
diff --git a/eaters-3.0.8/agents/counter example/counter.vsa b/eaters-3.0.8/agents/counter example/counter.vsa
new file mode 100644
index 0000000..86e5e9b
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter.vsa
@@ -0,0 +1,10 @@
+Version 1
+\counter\counter.dm
+0 ROOT counter counter
+1 0 FILE _firstload _firstload.soar
+2 0 FOLDER all all
+3 0 FOLDER common common
+4 0 OPERATOR count count.soar
+5 0 FOLDER elaborations elaborations
+6 5 FILE elaborations elaborations.soar
+7 0 OPERATOR init-count init-count.soar
diff --git a/eaters-3.0.8/agents/counter example/counter/_firstload.soar b/eaters-3.0.8/agents/counter example/counter/_firstload.soar
new file mode 100644
index 0000000..e69de29
diff --git a/eaters-3.0.8/agents/counter example/counter/count.soar b/eaters-3.0.8/agents/counter example/counter/count.soar
new file mode 100644
index 0000000..fbcf2a5
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter/count.soar
@@ -0,0 +1,15 @@
+sp {counter*propose*count
+ (state ^name counter)
+ -->
+ ( ^operator + =, <)
+ ( ^name count)
+}
+
+sp {apply*count
+ (state ^operator
+ ^count )
+ ( ^name count)
+ -->
+ ( ^count -
+ (+ 1))
+}
diff --git a/eaters-3.0.8/agents/counter example/counter/counter.dm b/eaters-3.0.8/agents/counter example/counter/counter.dm
new file mode 100644
index 0000000..def4865
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter/counter.dm
@@ -0,0 +1,22 @@
+10
+SOAR_ID 0
+ENUMERATION 1 1 state
+ENUMERATION 2 1 nil
+ENUMERATION 3 1 counter
+SOAR_ID 4
+ENUMERATION 5 1 init-count
+INTEGER 6
+SOAR_ID 7
+ENUMERATION 8 1 count
+INTEGER 9
+10
+0 count 6
+0 name 3
+0 operator 7
+0 operator 4
+0 superstate 2
+0 top-state 0
+0 type 1
+4 name 5
+7 count 9
+7 name 8
diff --git a/eaters-3.0.8/agents/counter example/counter/counter_source.soar b/eaters-3.0.8/agents/counter example/counter/counter_source.soar
new file mode 100644
index 0000000..57041b5
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter/counter_source.soar
@@ -0,0 +1,6 @@
+source _firstload.soar
+source count.soar
+pushd elaborations
+source elaborations_source.soar
+popd
+source init-count.soar
diff --git a/eaters-3.0.8/agents/counter example/counter/elaborations/elaborations.soar b/eaters-3.0.8/agents/counter example/counter/elaborations/elaborations.soar
new file mode 100644
index 0000000..54262b7
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter/elaborations/elaborations.soar
@@ -0,0 +1,4 @@
+sp {elaborations*elaborate*state
+ (state ^superstate nil)
+ -->
+ ( ^name counter)}
\ No newline at end of file
diff --git a/eaters-3.0.8/agents/counter example/counter/elaborations/elaborations_source.soar b/eaters-3.0.8/agents/counter example/counter/elaborations/elaborations_source.soar
new file mode 100644
index 0000000..50ab400
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter/elaborations/elaborations_source.soar
@@ -0,0 +1 @@
+source elaborations.soar
diff --git a/eaters-3.0.8/agents/counter example/counter/init-count.soar b/eaters-3.0.8/agents/counter example/counter/init-count.soar
new file mode 100644
index 0000000..9c0de60
--- /dev/null
+++ b/eaters-3.0.8/agents/counter example/counter/init-count.soar
@@ -0,0 +1,14 @@
+sp {counter*propose*init-count
+ (state ^name counter
+ -^count)
+ -->
+ ( ^operator + =)
+ ( ^name init-count)
+}
+
+sp {apply*init-count
+ (state ^operator )
+ ( ^name init-count)
+ -->
+ ( ^count 0)
+}
diff --git a/eaters-3.0.8/agents/eater-default.soar b/eaters-3.0.8/agents/eater-default.soar
new file mode 100644
index 0000000..d800c2e
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default.soar
@@ -0,0 +1,3 @@
+pushd eater-default
+source eater-default_source.soar
+popd
diff --git a/eaters-3.0.8/agents/eater-default.vsa b/eaters-3.0.8/agents/eater-default.vsa
new file mode 100644
index 0000000..2764b2d
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default.vsa
@@ -0,0 +1,9 @@
+VERSION 4
+\eater-default\eater-default.dm
+0 ROOT eater-default eater-default 1
+1 0 FOPERATOR _firstload _firstload.soar 3
+2 0 FOLDER all all 4
+3 0 FOLDER elaborations elaborations 2
+4 3 FOPERATOR _all _all.soar 5
+5 3 FOPERATOR top-state top-state.soar 6
+END
diff --git a/eaters-3.0.8/agents/eater-default/_firstload.soar b/eaters-3.0.8/agents/eater-default/_firstload.soar
new file mode 100644
index 0000000..e69de29
diff --git a/eaters-3.0.8/agents/eater-default/all/all_source.soar b/eaters-3.0.8/agents/eater-default/all/all_source.soar
new file mode 100644
index 0000000..e69de29
diff --git a/eaters-3.0.8/agents/eater-default/comment.dm b/eaters-3.0.8/agents/eater-default/comment.dm
new file mode 100644
index 0000000..81dc845
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default/comment.dm
@@ -0,0 +1,23 @@
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
diff --git a/eaters-3.0.8/agents/eater-default/eater-default.dm b/eaters-3.0.8/agents/eater-default/eater-default.dm
new file mode 100644
index 0000000..2dfd7a2
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default/eater-default.dm
@@ -0,0 +1,43 @@
+18
+SOAR_ID 0
+SOAR_ID 1
+SOAR_ID 2
+SOAR_ID 3
+ENUMERATION 4 1 state
+ENUMERATION 5 1 nil
+ENUMERATION 6 1 eater-default
+SOAR_ID 7
+ENUMERATION 8 1 complete
+ENUMERATION 9 4 east north south west
+SOAR_ID 10
+ENUMERATION 11 5 bonusfood eater empty normalfood wall
+SOAR_ID 12
+ENUMERATION 13 4 east north south west
+ENUMERATION 14 5 black blue purple red yellow
+INTEGER_RANGE 15 -2147483648 2147483647
+INTEGER_RANGE 16 -2147483648 2147483647
+INTEGER_RANGE 17 -2147483648 2147483647
+23
+0 io 1
+0 name 6
+0 superstate 5
+0 top-state 0
+0 type 4
+1 input-link 2
+1 output-link 3
+2 eater 12
+2 my-location 10
+3 jump 7
+3 move 7
+7 direction 9
+7 status 8
+10 content 11
+10 east 10
+10 north 10
+10 south 10
+10 west 10
+12 direction 13
+12 name 14
+12 score 15
+12 x 16
+12 y 17
diff --git a/eaters-3.0.8/agents/eater-default/eater-default_source.soar b/eaters-3.0.8/agents/eater-default/eater-default_source.soar
new file mode 100644
index 0000000..9947dbe
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default/eater-default_source.soar
@@ -0,0 +1,7 @@
+source _firstload.soar
+pushd all
+source all_source.soar
+popd
+pushd elaborations
+source elaborations_source.soar
+popd
diff --git a/eaters-3.0.8/agents/eater-default/elaborations/_all.soar b/eaters-3.0.8/agents/eater-default/elaborations/_all.soar
new file mode 100644
index 0000000..571b0d1
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default/elaborations/_all.soar
@@ -0,0 +1,12 @@
+sp {elaborate*state*name
+ (state ^superstate.operator.name )
+-->
+ ( ^name )
+}
+
+sp {elaborate*state*top-state
+ (state ^superstate.top-state )
+-->
+ ( ^top-state )
+}
+
diff --git a/eaters-3.0.8/agents/eater-default/elaborations/elaborations_source.soar b/eaters-3.0.8/agents/eater-default/elaborations/elaborations_source.soar
new file mode 100644
index 0000000..48f7de1
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default/elaborations/elaborations_source.soar
@@ -0,0 +1,2 @@
+source _all.soar
+source top-state.soar
diff --git a/eaters-3.0.8/agents/eater-default/elaborations/top-state.soar b/eaters-3.0.8/agents/eater-default/elaborations/top-state.soar
new file mode 100644
index 0000000..4127a9a
--- /dev/null
+++ b/eaters-3.0.8/agents/eater-default/elaborations/top-state.soar
@@ -0,0 +1,12 @@
+sp {elaborate*top-state*name
+ (state ^superstate nil)
+-->
+ ( ^name eater-default)
+}
+
+sp {elaborate*top-state*top-state
+ (state ^name eater-default)
+-->
+ ( ^top-state )
+}
+
diff --git a/eaters-3.0.8/agents/tutorial/advanced-move.soar b/eaters-3.0.8/agents/tutorial/advanced-move.soar
new file mode 100644
index 0000000..52cfc24
--- /dev/null
+++ b/eaters-3.0.8/agents/tutorial/advanced-move.soar
@@ -0,0 +1,128 @@
+############################################################################
+# From Chapter 9 of Soar 8 Tutorial
+#
+# These are the final versions of the rules for the generalized advanced move
+# operator.
+
+sp {initialize*state*directions
+ (state ^type state)
+ -->
+ ( ^directions )
+ ( ^value north ^opposite south)
+ ( ^value east ^opposite west)
+ ( ^value south ^opposite north)
+ ( ^value west ^opposite east)}
+
+# Propose*move*no-backward:
+# If there is normalfood, bonusfood, eater, or empty in an adjacent cell,
+# and there is no last direction equal to the opposite direction for that # cell,
+# propose move in the direction of that cell, with the cell's content,
+# and indicate that this operator can be selected randomly.
+
+sp {propose*move*no-backward
+ (state ^io.input-link.my-location..content { <> wall }
+ ^directions
+ -^last-direction )
+ ( ^value
+ ^opposite )
+-->
+ ( ^operator +, =)
+ ( ^name move
+ ^direction
+ ^content )}
+
+# Apply*move
+# If the move operator for a direction is selected,
+# generate an output command to move in that direction.
+
+sp {apply*move
+ (state ^io.output-link
+ ^operator )
+ ( ^name move
+ ^direction )
+-->
+ (write | | )
+ ( ^move.direction )}
+
+# Apply*move*remove-move:
+# If the move operator is selected,
+# and there is a completed move command on the output link,
+# then remove that command.
+
+sp {apply*move*remove-move
+ (state ^io.output-link
+ ^operator.name move)
+ ( ^move )
+ ( ^status complete)
+-->
+ ( ^move -)}
+
+# Apply*move*create*last-direction
+# If the move operator for a direction is selected,
+# create an augmentation called last-direction with that direction.
+
+sp {apply*move*create*last-direction
+ (state ^operator )
+ ( ^name move
+ ^direction )
+-->
+ ( ^last-direction )}
+
+# Apply*move*remove*last-direction
+# If the move operator for a direction is selected,
+# and the last-direction is not equal to that direction,
+# then remove the last-direction.
+
+sp {apply*move*remove*last-direction
+ (state ^operator
+ ^last-direction )
+ ( ^direction <>
+ ^name move)
+-->
+ ( ^last-direction -)}
+
+# Select*move*bonusfood-better-than-normalfood
+# If there is a proposed operator to move to a cell with bonusfood and
+# there is a second proposed operator to move to a cell that is empty or
+# has normalfood
+# prefer the first operator.
+
+sp {select*move*bonusfood-better-than-normalfood-empty
+ (state ^operator +
+ ^operator +)
+ ( ^name move
+ ^content bonusfood)
+ ( ^name move
+ ^content << normalfood empty >>)
+-->
+ ( ^operator > )}
+
+# Select*move*avoid-empty-eater
+# If there is a proposed operator to move to an empty cell or a cell with
+# another eater,
+# then avoid that operator.
+
+sp {select*move*avoid-empty-eater
+ (state ^operator +)
+ ( ^name move
+ ^content << empty eater >>)
+-->
+ ( ^operator <)}
+
+# Select*move*reject*backward
+# If there is a proposed operator to move in the direction
+# opposite the last move,
+# reject that operator.
+
+
+sp {select*move*reject*backward
+ (state ^operator +
+ ^directions
+ ^last-direction )
+ ( ^value
+ ^opposite )
+ ( ^name move
+ ^direction )
+-->
+ (write | Reject | )
+ ( ^operator -)}
diff --git a/eaters-3.0.8/agents/tutorial/hello-world-operator.soar b/eaters-3.0.8/agents/tutorial/hello-world-operator.soar
new file mode 100644
index 0000000..f9446ee
--- /dev/null
+++ b/eaters-3.0.8/agents/tutorial/hello-world-operator.soar
@@ -0,0 +1,19 @@
+###########################################################################
+# From Chapter 3 of Soar 8 Tutorial
+#
+### This operator writes "Hello World" and halts.
+
+sp {propose*hello-world
+ (state ^type state)
+-->
+ ( ^operator +)
+ ( ^name hello-world)
+}
+
+sp {apply*hello-world
+ (state ^operator )
+ ( ^name hello-world)
+-->
+ (write |Hello World|)
+ (halt)
+}
diff --git a/eaters-3.0.8/agents/tutorial/hello-world-rule.soar b/eaters-3.0.8/agents/tutorial/hello-world-rule.soar
new file mode 100644
index 0000000..abc2cb6
--- /dev/null
+++ b/eaters-3.0.8/agents/tutorial/hello-world-rule.soar
@@ -0,0 +1,10 @@
+###########################################################################
+# From Chapter 2 of Soar 8 Tutorial
+### This rule writes "Hello World" and halts.
+
+sp {hello-world
+ (state ^type state)
+-->
+ (write |Hello World|)
+ (halt)
+}
diff --git a/eaters-3.0.8/agents/tutorial/jump-and-move.soar b/eaters-3.0.8/agents/tutorial/jump-and-move.soar
new file mode 100644
index 0000000..68bbfbe
--- /dev/null
+++ b/eaters-3.0.8/agents/tutorial/jump-and-move.soar
@@ -0,0 +1,78 @@
+############################################################################
+# From Chapter 10 of Soar 8 Tutorial
+#
+# These are the final versions of the rules for the jump and move operator.
+
+sp {initialize*state*directions
+ (state ^type state)
+ -->
+ ( ^directions )
+ ( ^value north ^opposite south)
+ ( ^value east ^opposite west)
+ ( ^value south ^opposite north)
+ ( ^value west ^opposite east)}
+
+sp {init*elaborate*name-content-value
+ (state ^type state)
+ -->
+ ( ^name-content-value
+ )
+ ( ^name move ^content empty ^value 0)
+ ( ^name move ^content eater ^value 0)
+ ( ^name move ^content normalfood ^value 5)
+ ( ^name move ^content bonusfood ^value 10)
+ ( ^name jump ^content empty ^value -5)
+ ( ^name jump ^content eater ^value -5)
+ ( ^name jump ^content normalfood ^value 0)
+ ( ^name jump ^content bonusfood ^value 5)}
+
+sp {propose*move
+ (state ^io.input-link.my-location..content { <> wall })
+-->
+ ( ^operator +, =)
+ ( ^name move
+ ^content
+ ^actions.move.direction )}
+
+sp {propose*jump
+ (state ^io.input-link.my-location...content { <> wall })
+-->
+ ( ^operator +, =)
+ ( ^name jump
+ ^content
+ ^actions.jump.direction )}
+
+sp {elaborate*operator*value
+ (state ^operator +
+ ^name-content-value )
+ ( ^name ^content )
+ ( ^name ^content ^value )
+ -->
+ ( ^value )}
+
+sp {select*compare*best*value
+ (state ^operator +
+ ^operator +)
+ ( ^value )
+ ( ^value < )
+-->
+ ( ^operator > )}
+
+
+## General operator application rules
+
+sp {apply*operator*create-action-command
+ (state ^operator
+ ^io.output-link )
+ ( ^actions )
+ ( ^)
+-->
+ ( ^)}
+
+sp {apply*operator*remove-command
+ (state ^operator.actions
+ ^io.output-link )
+ ( ^)
+ ( ^status complete)
+-->
+ ( ^ -)}
diff --git a/eaters-3.0.8/agents/tutorial/jump.soar b/eaters-3.0.8/agents/tutorial/jump.soar
new file mode 100644
index 0000000..4bd0f05
--- /dev/null
+++ b/eaters-3.0.8/agents/tutorial/jump.soar
@@ -0,0 +1,56 @@
+############################################################################
+# From Chapter 10 of Soar 8 Tutorial
+#
+# These are the final versions of the rules for the jump operator.
+# These can be loaded in with the advanced move operator
+
+sp {initialize*state*directions
+ (state ^type state)
+ -->
+ ( ^directions
+ ^directions
+ ^directions
+ ^directions )
+ ( ^value north ^opposite south)
+ ( ^value east ^opposite west)
+ ( ^value south ^opposite north)
+ ( ^value west ^opposite east)}
+
+# Propose*jump:
+# If the content of a cell two steps away in a direction is not a wall,
+# propose jump in the direction of that cell, with the cell's content,
+# and indicate that this operator can be selected randomly.
+
+sp {propose*jump
+ (state ^io.input-link.my-location...content
+ { <> wall })
+-->
+ ( ^operator +, =)
+ ( ^name jump
+ ^direction
+ ^content )}
+
+# Apply*move*jump
+# If the move or jump operator for a direction is selected,
+# generate an output name to move in that direction.
+
+sp {apply*move
+ (state