Author Topic: Soft Arrays grand tour (with video!)  (Read 2778 times)

0 Members and 1 Guest are viewing this topic.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Soft Arrays grand tour (with video!)
« on: December 22, 2020, 03:09:12 pm »
I felt bad for not really explaining the linked lists thing in another post, so I'm making it all up to you you here.

(1) A video ~ 15 mins:


(2) Full code, no attachments, just paste and F5. You can follow with the video.

Code: QB64: [Select]
  1. ' Version 2020-12-22
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  14. ' Begin BI-component.
  15. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  16.  
  17. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  18. ' Hard arrays to store actual data:
  19. '
  20. REDIM SHARED IntegerData(0) AS INTEGER
  21. REDIM SHARED TextData(0) AS STRING
  22. REDIM SHARED DoubleData(0) AS DOUBLE
  23.  
  24. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  25. ' Temp variable(s):
  26. '
  27.  
  28. DIM ktmpsa AS INTEGER
  29.  
  30. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  31. ' Nodes:
  32. '
  33.  
  34. ' Node structure
  35. TYPE Node
  36.     Identity AS LONG '   Address in identity register
  37.     Species AS STRING '  Data type
  38.     Reference AS LONG '  Pointer to hard array index
  39.     North AS LONG '
  40.     South AS LONG '
  41.     East AS LONG '
  42.     West AS LONG '       Orientation
  43.  
  44. DIM MaxNodes AS INTEGER
  45. MaxNodes = 10000
  46.  
  47. ' Node identity register
  48. DIM SHARED IdentityRegister(MaxNodes) AS LONG
  49. FOR ktmpsa = 1 TO UBOUND(IdentityRegister)
  50.     IdentityRegister(ktmpsa) = -1
  51.  
  52. ' Node storage
  53. DIM SHARED Nodes(MaxNodes) AS Node
  54.  
  55. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  56. ' Soft arrays:
  57. '
  58.  
  59. ' Soft array structure
  60. TYPE SoftArrayStructure
  61.     Label AS STRING
  62.     HeadNode AS LONG
  63.  
  64. DIM MaxSoftArrays AS INTEGER
  65. MaxSoftArrays = MaxNodes / 2
  66.  
  67. ' Soft array register
  68. DIM SHARED SoftArrayRegister(MaxSoftArrays) AS INTEGER
  69. FOR ktmpsa = 1 TO UBOUND(SoftArrayRegister)
  70.     SoftArrayRegister(ktmpsa) = -1
  71.  
  72. ' Soft array storage
  73. DIM SHARED SoftArray(MaxSoftArrays) AS SoftArrayStructure
  74.  
  75. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  76. ' Processing
  77. '
  78. DIM SHARED LambdaMatrix(99, 9) AS LONG
  79. DIM SHARED LambdaIndex AS INTEGER
  80. DIM SHARED LambdaArgCount(9) AS LONG
  81. LambdaIndex = 0
  82.  
  83. DIM SHARED IdentityStack(MaxNodes, 5) AS LONG
  84. DIM SHARED IdentityStackSize AS INTEGER
  85.  
  86.  
  87. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  88. ' End BI-component.
  89. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100. 'REM $Include: 'SoftArrays.bi'
  101.  
  102. _TITLE "Soft Array Editor"
  103.  
  104. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  105. ' Meta:
  106. '
  107.  
  108. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  109. ' Visual Nodes (optional)
  110. '
  111.  
  112. TYPE Vector
  113.     x AS DOUBLE
  114.     y AS DOUBLE
  115.  
  116. ' Visual node structure
  117. TYPE VisualNodesStructure
  118.     Reference AS LONG '    Points to a node.
  119.     BoxCenter AS Vector
  120.     BoxHeight AS DOUBLE
  121.     BoxWidth AS DOUBLE
  122.     CornerNE AS Vector
  123.     CornerNW AS Vector
  124.     CornerSE AS Vector
  125.     CornerSW AS Vector
  126.     AntennaN AS Vector
  127.     AntennaS AS Vector
  128.     AntennaE AS Vector
  129.     AntennaW AS Vector
  130.     Visible AS INTEGER
  131.  
  132. DIM MaxVisualNodess AS INTEGER
  133. DIM SHARED VisualNodesCount AS INTEGER
  134. MaxVisualNodess = 512
  135. VisualNodesCount = 0
  136.  
  137. ' Visual node storage
  138. DIM SHARED VisualNodes(MaxVisualNodess) AS VisualNodesStructure
  139.  
  140. ' Visual node extras
  141. DIM SHARED SelectionIndex(5) AS INTEGER
  142.  
  143. DIM SHARED ScrollPosition AS Vector
  144. DIM SHARED Origin AS Vector
  145.  
  146. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  147. ' Pre-Main
  148. '
  149.  
  150. DIM SHARED ScreenHandle AS LONG
  151. DIM SHARED ScreenHandleTemp AS LONG
  152. 'ScreenHandle = _NEWIMAGE(800, 600, 32)
  153. ScreenHandle = _NEWIMAGE(1024, 768, 32)
  154. SCREEN ScreenHandle
  155. COLOR _RGBA(255, 255, 255, 255)
  156.  
  157. Origin.x = -.33 * _WIDTH / 2
  158. Origin.y = .9 * _HEIGHT / 2
  159. ScrollPosition.x = 0
  160. ScrollPosition.y = 0
  161.  
  162. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  163. ' Main
  164. '
  165.  
  166. 'SLEEP
  167. CALL UserMain(0, 1, 1)
  168. CALL DemoTree
  169. CALL DemoArray3D
  170. CALL DemoTreeEdit
  171. CALL DemoArithmetic
  172. CALL DemoList
  173. CALL DemoLambda
  174. CALL DemoMerge
  175. CALL DemoJSON
  176.  
  177.  
  178.  
  179. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  180. ' Demo cases:
  181. '
  182.  
  183. SUB DemoJSON
  184.     DIM TheName AS STRING
  185.     TheName = "myObj"
  186.  
  187.     DIM a AS LONG
  188.     DIM b AS LONG
  189.     DIM c AS LONG
  190.     DIM d AS LONG
  191.     DIM e AS LONG
  192.     a = NewSoftArray(TheName)
  193.     b = LinkEast(a, NewTextNode("name"))
  194.     c = LinkEast(b, NewTextNode("John"))
  195.     b = LinkSouth(b, NewTextNode("age"))
  196.     c = LinkEast(b, NewIntegerNode(30))
  197.     b = LinkSouth(b, NewTextNode("cars"))
  198.     c = LinkEast(b, NewTextNode("[]"))
  199.     c = LinkSouth(c, NewTextNode("{}"))
  200.     d = LinkEast(c, NewTextNode("name"))
  201.     e = LinkEast(d, NewTextNode("Ford"))
  202.     d = LinkSouth(d, NewTextNode("models"))
  203.     e = LinkEast(d, NewTextNode("[]"))
  204.     e = LinkSouth(e, NewTextNode("Fiesta"))
  205.     e = LinkSouth(e, NewTextNode("Focus"))
  206.     e = LinkSouth(e, NewTextNode("Mustang"))
  207.     c = LinkSouth(c, NewTextNode("{}"))
  208.     d = LinkEast(c, NewTextNode("name"))
  209.     e = LinkEast(d, NewTextNode("BMW"))
  210.     d = LinkSouth(d, NewTextNode("models"))
  211.     e = LinkEast(d, NewTextNode("[]"))
  212.     e = LinkSouth(e, NewTextNode("320"))
  213.     e = LinkSouth(e, NewTextNode("X3"))
  214.     e = LinkSouth(e, NewTextNode("X5"))
  215.     c = LinkSouth(c, NewTextNode("{}"))
  216.     d = LinkEast(c, NewTextNode("name"))
  217.     e = LinkEast(d, NewTextNode("Fiat"))
  218.     d = LinkSouth(d, NewTextNode("models"))
  219.     e = LinkEast(d, NewTextNode("[]"))
  220.     e = LinkSouth(e, NewTextNode("500"))
  221.     e = LinkSouth(e, NewTextNode("Panda"))
  222.  
  223.     CALL UserMain(0, 1, 1)
  224.  
  225. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  226.  
  227. SUB DemoTree
  228.     DIM TheName AS STRING
  229.     TheName = "Tree of Friends"
  230.  
  231.     DIM a AS LONG
  232.     DIM b AS LONG
  233.     DIM c AS LONG
  234.     DIM d AS LONG
  235.     DIM e AS LONG
  236.     DIM f AS LONG
  237.     DIM g AS LONG
  238.  
  239.     a = NewSoftArray(TheName)
  240.     b = LinkEast(a, NewTextNode("QB64 Buddy"))
  241.     c = LinkEast(b, NewTextNode("Handle"))
  242.     d = LinkEast(c, NewTextNode("SMcNeill"))
  243.     c = LinkSouth(c, NewTextNode("Name"))
  244.     d = LinkEast(c, NewTextNode("Steve SMcNeill"))
  245.     c = LinkSouth(c, NewTextNode("Country"))
  246.     d = LinkEast(c, NewTextNode("USA"))
  247.     e = LinkEast(d, NewTextNode("Locality"))
  248.     f = LinkEast(e, NewTextNode("Virginia"))
  249.     c = LinkSouth(c, NewTextNode("Birthyear"))
  250.     d = LinkEast(c, NewIntegerNode(1973))
  251.     d = LinkSouth(d, NewTextNode("May?"))
  252.     b = LinkSouth(b, NewTextNode("QB64 Buddy"))
  253.     c = LinkEast(b, NewTextNode("Handle"))
  254.     d = LinkEast(c, NewTextNode("FellippeHeitor"))
  255.     c = LinkSouth(c, NewTextNode("Name"))
  256.     d = LinkEast(c, NewTextNode("Fellippe Heitor"))
  257.     c = LinkSouth(c, NewTextNode("Country"))
  258.     d = LinkEast(c, NewTextNode("Brazil"))
  259.     e = LinkEast(d, NewTextNode("Locality"))
  260.     f = LinkEast(e, NewTextNode("My <3"))
  261.     g = LinkEast(f, NewTextNode("JK, it's ___."))
  262.     c = LinkSouth(c, NewTextNode("Birthyear"))
  263.     d = LinkEast(c, NewIntegerNode(1983))
  264.     d = LinkSouth(d, NewTextNode("Sep?"))
  265.     d = LinkSouth(d, NewTextNode("... or was it May?"))
  266.     b = LinkSouth(b, NewTextNode("QB64 Buddy"))
  267.     c = LinkEast(b, NewTextNode("Handle"))
  268.     d = LinkEast(c, NewTextNode("Ashish"))
  269.  
  270.     ' Query tests
  271.     CLS
  272.     PRINT PrintSoftArray$(a)
  273.     PRINT
  274.     PRINT "Steve's locality: ";
  275.     PRINT Literal$(StepFromUsing(a, "eesseee"))
  276.     PRINT "Fellippe's locality: ";
  277.     PRINT Literal$(StepFromUsing(a, "esesseee"))
  278.     PRINT "Fellippe's birth month: ";
  279.     PRINT Literal$(StepFromUsing(JumpFrom(StepFromUsing(a, "ese"), "s", 3), "es"))
  280.     PRINT "Width of Fellippe's Country branch:";
  281.     PRINT Measure(SeekText("Country", a, 2), "e")
  282.     PRINT "Height under Fellippe's Birthyear branch:";
  283.     PRINT Measure(Nodes(SeekText("Birthyear", a, 2)).East, "s")
  284.     PRINT
  285.     PRINT "Press any key..."
  286.     _DISPLAY
  287.     SLEEP
  288.  
  289.     CALL UserMain(0, 1, 1)
  290.  
  291. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  292.  
  293. SUB DemoArray3D
  294.     DIM TheName AS STRING
  295.     TheName = "Three-Dimensional Array"
  296.  
  297.     DIM i AS INTEGER
  298.     DIM j AS INTEGER
  299.     DIM k AS INTEGER
  300.     DIM a AS LONG
  301.     DIM b AS LONG
  302.  
  303.     ' Create a 3D array manually
  304.     DIM TestArray3D(3, 2, 3) AS STRING
  305.     TestArray3D(1, 1, 1) = "one.one.one"
  306.     TestArray3D(1, 1, 2) = "one.one.two"
  307.     TestArray3D(1, 1, 3) = "one.one.three"
  308.     TestArray3D(1, 2, 1) = "one.two.one"
  309.     TestArray3D(1, 2, 2) = "one.two.two"
  310.     TestArray3D(1, 2, 3) = "one.two.three"
  311.     TestArray3D(2, 1, 1) = "two.one.one"
  312.     TestArray3D(2, 1, 2) = "two.one.two"
  313.     TestArray3D(2, 1, 3) = "two.one.three"
  314.     TestArray3D(2, 2, 1) = "two.two.one"
  315.     TestArray3D(2, 2, 2) = "two.two.two"
  316.     TestArray3D(2, 2, 3) = "two.two.three"
  317.     TestArray3D(3, 1, 1) = "three.one.one"
  318.     TestArray3D(3, 1, 2) = "three.one.two"
  319.     TestArray3D(3, 1, 3) = "three.one.three"
  320.     TestArray3D(3, 2, 1) = "three.two.one"
  321.     TestArray3D(3, 2, 2) = "three.two.two"
  322.     TestArray3D(3, 2, 3) = "three.two.three"
  323.  
  324.     ' Load 3D array as Soft array
  325.     a = NewSoftArray(TheName)
  326.     FOR i = 1 TO UBOUND(TestArray3D, 1)
  327.         FOR j = 1 TO UBOUND(TestArray3D, 2)
  328.             FOR k = 1 TO UBOUND(TestArray3D, 3)
  329.                 IF ((i = 1) AND (j = 1) AND (k = 1)) THEN
  330.                     a = LinkEast(a, NewTextNode(TestArray3D(i, j, k)))
  331.                     b = a
  332.                 ELSE
  333.                     IF (k = 1) THEN
  334.                         a = LinkSouth(a, NewTextNode(TestArray3D(i, j, k)))
  335.                         b = a
  336.                     ELSE
  337.                         b = LinkEast(b, NewTextNode(TestArray3D(i, j, k)))
  338.                     END IF
  339.                 END IF
  340.             NEXT
  341.         NEXT
  342.     NEXT
  343.  
  344.     CLS
  345.  
  346.     ' Store the identity of the array name (even though we already have it, pretend we just received the label.)
  347.     DIM a0 AS LONG
  348.     a0 = SoftArrayID(TheName)
  349.     PRINT PrintSoftArray$(a0)
  350.     PRINT
  351.  
  352.     ' Store the address of he head node and print its content. This initializes the loop below.
  353.     k = SoftArray(a0).HeadNode
  354.  
  355.     PRINT "Typical FOR-like loop:"
  356.     PRINT Literal$(k)
  357.     PRINT "(Listing one layer deep only.)"
  358.     ' Set the address variable to the first entry in the "array".
  359.     k = Nodes(k).East
  360.     DO
  361.         PRINT Literal$(k)
  362.         k = Nodes(k).South
  363.         IF (k = -1) THEN EXIT DO
  364.         ' Exit the loop when there is no south link.
  365.     LOOP
  366.     _DISPLAY
  367.     SLEEP
  368.  
  369.     CALL UserMain(0, 1, 1)
  370.  
  371. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  372.  
  373. SUB DemoMerge
  374.     DIM TheName1 AS STRING
  375.     DIM TheName2 AS STRING
  376.     TheName1 = "top part"
  377.     TheName2 = "bottom part"
  378.  
  379.     DIM a AS LONG
  380.     DIM a0 AS LONG
  381.     DIM b AS LONG
  382.  
  383.     a = NewUnitArray("cow", NewIntegerNode(5))
  384.     a0 = a
  385.     a = NewSoftArray(TheName1)
  386.     a = LinkEast(a, NewTextNode("lambda"))
  387.     b = LinkEast(a, NewIntegerNode(4))
  388.     b = LinkSouth(b, NewIntegerNode(6))
  389.     a = NewSoftArray(TheName2)
  390.     a = LinkEast(a, NewTextNode("cos"))
  391.     b = LinkEast(a, NewTextNode("*"))
  392.     b = LinkEast(b, NewIntegerNode(3))
  393.     b = LinkSouth(b, NewTextNode("[1]"))
  394.     b = LinkSouth(b, CopyIntegerNode(Nodes(a0).East))
  395.     b = LinkSouth(b, NewTextNode("[2]"))
  396.  
  397.     CALL UserMain(1, 0, 0)
  398.  
  399.     a = SoftArrayID(TheName2)
  400.     b = SoftArray(a).HeadNode
  401.     SoftArrayRegister(a) = -1
  402.     IdentityRegister(b) = -1
  403.  
  404.     a = Nodes(SoftArray(SoftArrayID(TheName1)).HeadNode).East
  405.     b = Nodes(b).East
  406.     Nodes(b).West = -1
  407.     Nodes(b).North = a
  408.     Nodes(a).South = b
  409.  
  410.     CALL UserMain(1, 1, 0)
  411.     a = EvalMultiSoftArrays(1)
  412.     CALL UserMain(1, 0, 1)
  413.  
  414. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  415.  
  416. SUB DemoLambda
  417.     DIM TheName AS STRING
  418.     TheName = "Lambda Test"
  419.  
  420.     DIM a AS LONG
  421.     DIM a0 AS LONG
  422.     DIM b AS LONG
  423.     a = NewUnitArray("cow", NewIntegerNode(7))
  424.     a0 = a
  425.     a = NewSoftArray(TheName)
  426.     a = LinkEast(a, NewTextNode("lambda"))
  427.     b = LinkEast(a, NewIntegerNode(4))
  428.     b = LinkSouth(b, NewIntegerNode(6))
  429.     a = LinkSouth(a, NewTextNode("cos"))
  430.     b = LinkEast(a, NewTextNode("*"))
  431.     b = LinkEast(b, NewIntegerNode(3))
  432.     b = LinkSouth(b, NewTextNode("[1]"))
  433.     b = LinkSouth(b, CopyIntegerNode(Nodes(a0).East))
  434.     b = LinkSouth(b, NewTextNode("[2]"))
  435.  
  436.     CALL UserMain(0, 1, 0)
  437.     a = EvalMultiSoftArrays(1)
  438.     CALL UserMain(1, 0, 1)
  439.  
  440. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  441.  
  442. SUB DemoList
  443.     DIM TheName AS STRING
  444.     TheName = "List Test"
  445.  
  446.     DIM a AS LONG
  447.     DIM b AS LONG
  448.     a = NewSoftArray(TheName)
  449.     a = LinkEast(a, NewTextNode("cos"))
  450.     b = LinkEast(a, NewTextNode("three"))
  451.     b = LinkSouth(b, NewTextNode("four"))
  452.     b = LinkSouth(b, NewTextNode("five"))
  453.     b = LinkSouth(b, NewTextNode("six"))
  454.     b = LinkSouth(b, NewTextNode("seven"))
  455.     a = LinkSouth(a, NewTextNode("cos"))
  456.     b = LinkEast(a, NewIntegerNode(3))
  457.     b = LinkSouth(b, NewIntegerNode(4))
  458.     b = LinkSouth(b, NewIntegerNode(5))
  459.     b = LinkSouth(b, NewIntegerNode(6))
  460.     b = LinkSouth(b, NewIntegerNode(7))
  461.  
  462.     CALL UserMain(0, 1, 0)
  463.     a = EvalMultiSoftArrays(1)
  464.     CALL UserMain(1, 0, 1)
  465.  
  466. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  467.  
  468. SUB DemoArithmetic
  469.     DIM a AS LONG
  470.     DIM a0 AS LONG
  471.     DIM b AS LONG
  472.  
  473.     a = NewSoftArray("Arithmetic Test1")
  474.     a0 = a
  475.     a = LinkEast(a, NewTextNode("*"))
  476.     b = LinkEast(a, NewIntegerNode(3))
  477.     b = LinkSouth(b, NewIntegerNode(4))
  478.     a = LinkSouth(b, NewTextNode("cos"))
  479.     b = LinkEast(a, NewTextNode("+"))
  480.     b = LinkEast(b, NewIntegerNode(4))
  481.     b = LinkSouth(b, NewIntegerNode(7))
  482.     b = LinkSouth(a, NewIntegerNode(2))
  483.  
  484.     CALL UserMain(0, 1, 0)
  485.     a = EvalMultiSoftArrays(1)
  486.     CALL UserMain(1, 0, 0)
  487.  
  488.     a = NewSoftArray("Arithmetic Test2")
  489.     a = LinkEast(a, NewTextNode("/"))
  490.     b = LinkEast(a, NewIntegerNode(3))
  491.     a = LinkSouth(b, NewTextNode("cos"))
  492.     b = LinkEast(a, NewTextNode("+"))
  493.     b = LinkEast(b, NewIntegerNode(4))
  494.     b = LinkSouth(b, NewDoubleNode(DoubleData(Nodes(Nodes(a0).East).Reference)))
  495.  
  496.     CALL UserMain(0, 1, 0)
  497.     a = EvalMultiSoftArrays(1)
  498.     CALL UserMain(1, 0, 1)
  499.  
  500. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  501.  
  502. SUB DemoTreeEdit
  503.     DIM TheName AS STRING
  504.     TheName = "Tree Edit Test"
  505.  
  506.     DIM a AS LONG
  507.     DIM a0 AS LONG
  508.     DIM b AS LONG
  509.     DIM c AS LONG
  510.     a = NewSoftArray(TheName)
  511.     a0 = a
  512.     a = LinkEast(a, NewTextNode("QB64 Buddy"))
  513.     a = LinkEast(a, NewTextNode("Handle"))
  514.     b = LinkEast(a, NewTextNode("flukiluke"))
  515.     a = LinkSouth(a, NewTextNode("Name"))
  516.     b = LinkEast(a, NewTextNode("Luke C."))
  517.     a = LinkSouth(a, NewTextNode("Country"))
  518.     b = LinkEast(a, NewTextNode("Australia"))
  519.     c = LinkEast(b, NewTextNode("Locality"))
  520.     b = LinkEast(c, NewTextNode("Down Under"))
  521.     a = LinkSouth(a, NewTextNode("Birthyear"))
  522.     b = LinkEast(a, NewIntegerNode(1523))
  523.     c = LinkSouth(b, NewTextNode("December"))
  524.  
  525.     CALL UserMain(1, 0, 0)
  526.  
  527.     a = InsertEast(SeekText("Down Under", a0, 1), NewTextNode("Get it?"))
  528.     a = InsertSouth(SeekText("QB64 Buddy", a0, 1), NewTextNode("QB64 Enemy"))
  529.     a = EditIntegerReference(StepFromUsing(SeekText("Birthyear", a0, 1), "e"), 1855)
  530.     a = DeleteNodes(SeekText("Name", a0, 1))
  531.  
  532.     'CLS
  533.     '' Query tests
  534.     'PRINT "Inserting `Get it?' into list..."
  535.     'PRINT "Adding new entry to bottom of list..."
  536.     'PRINT "Editing Birthyear..."
  537.     'PRINT "Deleting Name..."
  538.     'PRINT
  539.     '_DISPLAY
  540.     'SLEEP
  541.  
  542.     CALL UserMain(0, 1, 1)
  543.  
  544. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  545. ' Begin GUI/Graphical component (optional)
  546. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  547.  
  548. SUB UserMain (q AS INTEGER, r AS INTEGER, s AS INTEGER)
  549.     DIM a AS LONG
  550.     DIM k AS INTEGER
  551.     DIM t AS STRING
  552.  
  553.     IF (q = 1) THEN
  554.         CLS
  555.         PRINT PrintMultiSoftArrays$(1)
  556.         CALL Halt
  557.     END IF
  558.  
  559.     IF (q = 2) THEN
  560.         CLS
  561.         PRINT PrintJSON$(1)
  562.         CALL Halt
  563.     END IF
  564.  
  565.     IF (r = 1) THEN
  566.         k = ClearSelections(1)
  567.         CALL BuildAllVisualArrays
  568.         CALL UserLoop
  569.     END IF
  570.  
  571.     IF (s = 1) THEN
  572.         a = DeleteAllSoftArrays(1)
  573.         k = ClearSelections(1)
  574.         ScrollPosition.x = 0
  575.         ScrollPosition.y = 0
  576.         t = MemoryProbe$("")
  577.     END IF
  578.  
  579. SUB UserLoop
  580.     DIM x0 AS DOUBLE
  581.     DIM y0 AS DOUBLE
  582.     DIM xx AS DOUBLE
  583.     DIM yy AS DOUBLE
  584.     DIM a AS LONG
  585.     DIM b AS LONG
  586.     DIM c AS LONG
  587.     DIM k AS INTEGER
  588.     DIM i AS INTEGER
  589.     DIM j AS INTEGER
  590.     DIM kh AS INTEGER
  591.     DIM AltWires AS INTEGER
  592.     DIM CtrlKey AS INTEGER
  593.     DIM MW AS INTEGER
  594.     DIM MB1 AS INTEGER
  595.     DIM t AS STRING
  596.     DIM KeyIn AS STRING
  597.  
  598.     KeyIn = INKEY$
  599.  
  600.     DO WHILE _MOUSEINPUT: LOOP ' Clear mouse buffer.
  601.  
  602.     DO
  603.  
  604.         x0 = _MOUSEX
  605.         y0 = _MOUSEY
  606.         x0 = (x0 - _WIDTH / 2)
  607.         y0 = (-y0 + _HEIGHT / 2)
  608.         i = MouseOver(x0, y0)
  609.  
  610.         MB1 = 0
  611.  
  612.         DO WHILE _MOUSEINPUT
  613.             xx = _MOUSEX
  614.             yy = _MOUSEY
  615.  
  616.             xx = (xx - _WIDTH / 2)
  617.             yy = (-yy + _HEIGHT / 2)
  618.  
  619.             IF ((_MOUSEBUTTON(1) = 0) AND (MB1 = 0)) THEN
  620.                 i = MouseOver(xx, yy)
  621.                 j = i
  622.             END IF
  623.  
  624.             IF ((_MOUSEBUTTON(1) = -1) AND (MB1 = 0)) THEN
  625.                 i = MouseOver(xx, yy)
  626.                 j = i
  627.                 MB1 = -1
  628.             END IF
  629.  
  630.             IF (MB1 = -1) THEN
  631.                 i = j
  632.                 IF (i <> -1) THEN
  633.                     'ScrollPosition.x = ScrollPosition.x + (xx - VisualNodes(i).BoxCenter.x)
  634.                     'ScrollPosition.y = ScrollPosition.y + (yy - VisualNodes(i).BoxCenter.y)
  635.                     'CALL MoveVisualNodesRecur(i, VisualNodes(i).Reference, xx - VisualNodes(i).BoxCenter.x, yy - VisualNodes(i).BoxCenter.y)
  636.                     CALL NewSelection(i)
  637.                 END IF
  638.             END IF
  639.  
  640.             '''
  641.  
  642.             IF (_MOUSEBUTTON(2) = -1) THEN
  643.                 ScrollPosition.x = ScrollPosition.x + (xx - x0)
  644.                 ScrollPosition.y = ScrollPosition.y + (yy - y0)
  645.                 CALL MoveAllVisualNodes(xx - x0, yy - y0)
  646.                 x0 = xx
  647.                 y0 = yy
  648.             END IF
  649.  
  650.             MW = _MOUSEWHEEL
  651.             IF (MW <> 0) THEN
  652.                 CALL MoveAllVisualNodes(0, 30 * MW)
  653.                 ScrollPosition.y = ScrollPosition.y + 30 * MW
  654.             END IF
  655.  
  656.         LOOP
  657.  
  658.         'IF ((_MOUSEBUTTON(1) = 0) AND (MB1 = -1)) THEN
  659.         IF (MB1 = -1) THEN
  660.             i = -1
  661.             j = i
  662.             MB1 = 0
  663.             CALL BuildAllVisualArrays
  664.         END IF
  665.  
  666.         IF (i <> -1) THEN
  667.             IF (xx > VisualNodes(i).BoxCenter.x - VisualNodes(i).BoxWidth / 2) AND (xx < VisualNodes(i).BoxCenter.x + VisualNodes(i).BoxWidth / 2) THEN
  668.                 IF (yy > VisualNodes(i).BoxCenter.y - VisualNodes(i).BoxHeight / 2) AND (yy < VisualNodes(i).BoxCenter.y + VisualNodes(i).BoxHeight / 2) THEN
  669.                     'CALL NewSelection(i)
  670.                 END IF
  671.             END IF
  672.         END IF
  673.  
  674.         kh = _KEYHIT
  675.  
  676.         ' Press-and-hold keys
  677.         IF (_KEYDOWN(100305)) OR (_KEYDOWN(100306)) THEN
  678.             CtrlKey = 1
  679.         ELSE
  680.             CtrlKey = 0
  681.         END IF
  682.  
  683.         IF (_KEYDOWN(ASC("w"))) OR (_KEYDOWN(ASC("W"))) THEN
  684.             AltWires = 1
  685.         ELSE
  686.             AltWires = 0
  687.         END IF
  688.  
  689.         ' State-changing.
  690.         SELECT CASE kh
  691.             CASE 13 ' enter
  692.                 IF (SelectionIndex(1) <> -1) THEN
  693.                     a = Evaluate(VisualNodes(SelectionIndex(1)).Reference)
  694.                     CALL BuildAllVisualArrays
  695.                     i = ClearSelections(1)
  696.                 END IF
  697.             CASE 27 ' esc
  698.                 EXIT SUB
  699.             CASE 21248 ' delete
  700.                 IF (SelectionIndex(1) <> -1) THEN
  701.                     a = DeleteNodes(VisualNodes(SelectionIndex(1)).Reference)
  702.                     CALL BuildAllVisualArrays
  703.                     i = ClearSelections(1)
  704.                 END IF
  705.             CASE ASC("v"), ASC("V")
  706.                 IF (SelectionIndex(1) <> -1) THEN
  707.                     a = SeverSoftArray(VisualNodes(SelectionIndex(1)).Reference)
  708.                     CALL BuildAllVisualArrays
  709.                 END IF
  710.             CASE ASC("c"), ASC("C")
  711.                 IF (SelectionIndex(1) <> -1) THEN
  712.                     a = CopyNodes(VisualNodes(SelectionIndex(1)).Reference)
  713.                     CALL BuildAllVisualArrays
  714.                 END IF
  715.             CASE ASC("i"), ASC("I")
  716.                 IF (CtrlKey = 1) THEN
  717.                     IF (SelectionIndex(1) <> -1) THEN
  718.                         a = ConvertToInteger(VisualNodes(SelectionIndex(1)).Reference, 0)
  719.                         CALL DefineVisualNode(SelectionIndex(1), VisualNodes(SelectionIndex(1)).Reference, VisualNodes(SelectionIndex(1)).BoxCenter.x, VisualNodes(SelectionIndex(1)).BoxCenter.y)
  720.                     END IF
  721.                 ELSE
  722.                     a = NewUnitArray("integer" + LTRIM$(RTRIM$(STR$(INT(TIMER * 10)))), NewIntegerNode(0))
  723.                     CALL BuildAllVisualArrays
  724.                 END IF
  725.             CASE ASC("d"), ASC("D")
  726.                 IF (CtrlKey = 1) THEN
  727.                     IF (SelectionIndex(1) <> -1) THEN
  728.                         a = ConvertToDouble(VisualNodes(SelectionIndex(1)).Reference, 0)
  729.                         CALL DefineVisualNode(SelectionIndex(1), VisualNodes(SelectionIndex(1)).Reference, VisualNodes(SelectionIndex(1)).BoxCenter.x, VisualNodes(SelectionIndex(1)).BoxCenter.y)
  730.                     END IF
  731.                 ELSE
  732.                     a = NewUnitArray("double" + LTRIM$(RTRIM$(STR$(INT(TIMER * 10)))), NewDoubleNode(0))
  733.                     CALL BuildAllVisualArrays
  734.                 END IF
  735.             CASE ASC("t"), ASC("T")
  736.                 IF (CtrlKey = 1) THEN
  737.                     IF (SelectionIndex(1) <> -1) THEN
  738.                         a = ConvertToText(VisualNodes(SelectionIndex(1)).Reference, "text")
  739.                         CALL DefineVisualNode(SelectionIndex(1), VisualNodes(SelectionIndex(1)).Reference, VisualNodes(SelectionIndex(1)).BoxCenter.x, VisualNodes(SelectionIndex(1)).BoxCenter.y)
  740.                     END IF
  741.                 ELSE
  742.                     a = NewUnitArray("text" + LTRIM$(RTRIM$(STR$(INT(TIMER * 10)))), NewTextNode("."))
  743.                     CALL BuildAllVisualArrays
  744.                 END IF
  745.             CASE ASC("e"), ASC("E")
  746.                 IF (CtrlKey = 1) THEN
  747.                     FOR k = 1 TO UBOUND(SoftArrayRegister)
  748.                         IF (SoftArrayRegister(k) <> -1) THEN
  749.                             IF (SoftArray(k).Label = Literal$(VisualNodes(SelectionIndex(1)).Reference)) THEN
  750.                                 a = SoftArray(k).HeadNode
  751.                                 b = Nodes(a).East
  752.                                 Nodes(b).West = -1
  753.                                 SoftArrayRegister(k) = -1
  754.                                 IdentityRegister(a) = -1
  755.                                 a = VisualNodes(SelectionIndex(2)).Reference
  756.                                 c = Nodes(a).East
  757.                                 IF (c <> -1) THEN
  758.                                     c = DeleteNodes(c)
  759.                                 END IF
  760.                                 Nodes(a).East = b
  761.                                 Nodes(b).West = a
  762.                                 EXIT FOR
  763.                             END IF
  764.                         END IF
  765.                     NEXT
  766.                 ELSE
  767.                     IF (SelectionIndex(1) <> -1) THEN
  768.                         SELECT CASE Nodes(VisualNodes(SelectionIndex(1)).Reference).Species
  769.                             CASE "integer"
  770.                                 a = InsertEast(VisualNodes(SelectionIndex(1)).Reference, NewIntegerNode(0))
  771.                             CASE "text"
  772.                                 a = InsertEast(VisualNodes(SelectionIndex(1)).Reference, NewTextNode("e"))
  773.                             CASE "double"
  774.                                 a = InsertEast(VisualNodes(SelectionIndex(1)).Reference, NewDoubleNode(0))
  775.                         END SELECT
  776.                     END IF
  777.                 END IF
  778.                 CALL BuildAllVisualArrays
  779.             CASE ASC("s"), ASC("S")
  780.                 IF (CtrlKey = 1) THEN
  781.                     FOR k = 1 TO UBOUND(SoftArrayRegister)
  782.                         IF (SoftArrayRegister(k) <> -1) THEN
  783.                             IF (SoftArray(k).Label = Literal$(VisualNodes(SelectionIndex(1)).Reference)) THEN
  784.                                 a = SoftArray(k).HeadNode
  785.                                 b = Nodes(a).East
  786.                                 Nodes(b).West = -1
  787.                                 SoftArrayRegister(k) = -1
  788.                                 IdentityRegister(a) = -1
  789.                                 a = VisualNodes(SelectionIndex(2)).Reference
  790.                                 c = Nodes(a).South
  791.                                 IF (c <> -1) THEN
  792.                                     c = DeleteNodesRecur(c)
  793.                                 END IF
  794.                                 Nodes(a).South = b
  795.                                 Nodes(b).North = a
  796.                                 EXIT FOR
  797.                             END IF
  798.                         END IF
  799.                     NEXT
  800.                 ELSE
  801.                     IF (SelectionIndex(1) <> -1) THEN
  802.                         SELECT CASE Nodes(VisualNodes(SelectionIndex(1)).Reference).Species
  803.                             CASE "integer"
  804.                                 a = InsertSouth(VisualNodes(SelectionIndex(1)).Reference, NewIntegerNode(0))
  805.                             CASE "text"
  806.                                 a = InsertSouth(VisualNodes(SelectionIndex(1)).Reference, NewTextNode("s"))
  807.                             CASE "double"
  808.                                 a = InsertSouth(VisualNodes(SelectionIndex(1)).Reference, NewDoubleNode(0))
  809.                         END SELECT
  810.                     END IF
  811.                 END IF
  812.                 CALL BuildAllVisualArrays
  813.             CASE ASC("x"), ASC("X")
  814.                 IF (SelectionIndex(1) <> -1) THEN
  815.                     _KEYCLEAR
  816.                     LOCATE (_HEIGHT / 16) / 2, (_WIDTH / 8) / 2 - 8
  817.                     PRINT "Enter new value:" '+ CHR$(10) + SPACE$(20);
  818.                     LOCATE (_HEIGHT / 16) / 2 + 1, (_WIDTH / 8) / 2 - 8
  819.                     LINE INPUT t
  820.                     SELECT CASE Nodes(VisualNodes(SelectionIndex(1)).Reference).Species
  821.                         CASE "integer"
  822.                             Nodes(VisualNodes(SelectionIndex(1)).Reference).Reference = NewIntegerData(INT(VAL(t)))
  823.                         CASE "text"
  824.                             a = VisualNodes(SelectionIndex(1)).Reference
  825.                             Nodes(a).Reference = NewTextData(t)
  826.                             FOR k = 1 TO UBOUND(SoftArrayRegister)
  827.                                 IF (SoftArrayRegister(k) <> -1) THEN
  828.                                     IF (SoftArray(k).HeadNode = a) THEN
  829.                                         SoftArray(k).Label = t
  830.                                     END IF
  831.                                 END IF
  832.                             NEXT
  833.                         CASE "double"
  834.                             Nodes(VisualNodes(SelectionIndex(1)).Reference).Reference = NewDoubleData(VAL(t))
  835.                     END SELECT
  836.                     CALL DefineVisualNode(SelectionIndex(1), VisualNodes(SelectionIndex(1)).Reference, VisualNodes(SelectionIndex(1)).BoxCenter.x, VisualNodes(SelectionIndex(1)).BoxCenter.y)
  837.                     CALL BuildAllVisualArrays
  838.                 END IF
  839.         END SELECT
  840.  
  841.         ' Display-changing.
  842.  
  843.         KeyIn = INKEY$
  844.  
  845.         SELECT CASE LCASE$(KeyIn)
  846.             CASE CHR$(10) ' Ctrl+J
  847.                 OPEN "SoftArrays-" + LTRIM$(RTRIM$(STR$(INT(10 * TIMER)))) + ".txt" FOR OUTPUT AS #1
  848.                 PRINT #1, PrintJSON$(1)
  849.                 CLOSE #1
  850.                 CALL UserMain(2, 0, 0)
  851.         END SELECT
  852.  
  853.         SELECT CASE kh
  854.             CASE 18688 ' pgup
  855.                 CALL MoveAllVisualNodes(0, -.9 * _HEIGHT / 2)
  856.                 ScrollPosition.y = ScrollPosition.y - .9 * _HEIGHT / 2
  857.             CASE 20736 ' pgdn
  858.                 CALL MoveAllVisualNodes(0, .9 * _HEIGHT / 2)
  859.                 ScrollPosition.y = ScrollPosition.y + .9 * _HEIGHT / 2
  860.             CASE ASC("m"), ASC("M")
  861.                 CLS
  862.                 PRINT MemoryProbe$("")
  863.                 CALL Halt
  864.             CASE ASC("l"), ASC("L")
  865.                 IF (CtrlKey = 1) THEN
  866.                     OPEN "SoftArrays-" + LTRIM$(RTRIM$(STR$(INT(10 * TIMER)))) + ".txt" FOR OUTPUT AS #1
  867.                     PRINT #1, PrintMultiSoftArrays$(1)
  868.                     CLOSE #1
  869.                 END IF
  870.                 CALL UserMain(1, 0, 0)
  871.             CASE ASC("j"), ASC("J")
  872.                 CALL UserMain(2, 0, 0)
  873.             CASE ELSE
  874.         END SELECT
  875.  
  876.         _KEYCLEAR
  877.  
  878.         IF (_RESIZE = -1) THEN
  879.             IF ((_RESIZEWIDTH > 320) AND (_RESIZEHEIGHT > 240)) THEN
  880.                 _DELAY .01
  881.                 ScreenHandleTemp = ScreenHandle
  882.                 ScreenHandle = _NEWIMAGE(_RESIZEWIDTH, _RESIZEHEIGHT, 32)
  883.                 SCREEN ScreenHandle
  884.                 _FREEIMAGE ScreenHandleTemp
  885.             END IF
  886.         END IF
  887.  
  888.         CLS
  889.  
  890.         CALL DrawAllVisualNodes(AltWires)
  891.  
  892.         IF (i <> -1) THEN
  893.             IF (VisualNodes(i).Reference <> -1) THEN
  894.                 CALL DrawSingleNode(i, _RGBA(255, 25, 50, 255), _RGBA(255, 255, 0, 255))
  895.             END IF
  896.         END IF
  897.  
  898.         COLOR _RGBA(200, 200, 200, 255)
  899.         CALL lprintstring(1, 3, "Selection history:")
  900.         FOR k = 1 TO UBOUND(SelectionIndex)
  901.             IF (SelectionIndex(k) <> -1) THEN
  902.                 IF (VisualNodes(SelectionIndex(k)).Reference <> -1) THEN
  903.                     CALL lprintstring(1, 3 + k, LTRIM$(RTRIM$(STR$(k))) + ") " + Literal$(VisualNodes(SelectionIndex(k)).Reference) + " (@ " + LTRIM$(RTRIM$(STR$(VisualNodes(SelectionIndex(k)).Reference))) + ")")
  904.                 END IF
  905.             END IF
  906.         NEXT
  907.  
  908.         COLOR _RGBA(200, 200, 200, 255)
  909.         i = UBOUND(SelectionIndex) + 4
  910.         i = i + 1: CALL lprintstring(1, i, "Mouse:")
  911.         i = i + 1: CALL lprintstring(1, i, "  Point  = highlight")
  912.         i = i + 1: CALL lprintstring(1, i, "  MB1    = select")
  913.         i = i + 1: CALL lprintstring(1, i, "  MB2    = drag")
  914.         i = i + 1: CALL lprintstring(1, i, "Soft arrays:")
  915.         i = i + 1: CALL lprintstring(1, i, "  I      = new integer")
  916.         i = i + 1: CALL lprintstring(1, i, "  T      = new text")
  917.         i = i + 1: CALL lprintstring(1, i, "  D      = new double")
  918.         i = i + 1: CALL lprintstring(1, i, "  C      = copy recur")
  919.         i = i + 1: CALL lprintstring(1, i, "  Delete = delete")
  920.         i = i + 1: CALL lprintstring(1, i, "  V      = sever")
  921.         i = i + 1: CALL lprintstring(1, i, "  Ctrl+S = mov (1)s(2)")
  922.         i = i + 1: CALL lprintstring(1, i, "  Ctrl+E = mov (1)e(2)")
  923.         i = i + 1: CALL lprintstring(1, i, "  Enter  = evaluate")
  924.         i = i + 1: CALL lprintstring(1, i, "Nodes:")
  925.         i = i + 1: CALL lprintstring(1, i, "  E      = append east")
  926.         i = i + 1: CALL lprintstring(1, i, "  S      = append south")
  927.         i = i + 1: CALL lprintstring(1, i, "  X      = edit content")
  928.         i = i + 1: CALL lprintstring(1, i, "  Ctrl+I = to integer")
  929.         i = i + 1: CALL lprintstring(1, i, "  Ctrl+T = to text")
  930.         i = i + 1: CALL lprintstring(1, i, "  Ctrl+D = to double")
  931.         i = i + 1: CALL lprintstring(1, i, "Report:")
  932.         i = i + 1: CALL lprintstring(1, i, "  L      = print all")
  933.         i = i + 1: CALL lprintstring(1, i, "  J      = print JSON")
  934.         i = i + 1: CALL lprintstring(1, i, "  Ctrl+L = write file")
  935.         COLOR _RGBA(255, 100, 155, 255)
  936.         i = i + 1: CALL lprintstring(1, i, "  Ctrl+J = write JSON")
  937.         COLOR _RGBA(200, 200, 200, 255)
  938.         i = i + 1: CALL lprintstring(1, i, "  M      = mem probe")
  939.         i = i + 1: CALL lprintstring(1, i, "  W      = all wires")
  940.  
  941.  
  942.         CALL rprintstring(3, "Scroll position:")
  943.         CALL rprintstring(4, "(" + LTRIM$(RTRIM$(STR$(INT(ScrollPosition.x)))) + "," + LTRIM$(RTRIM$(STR$(INT(ScrollPosition.y)))) + ")")
  944.  
  945.         COLOR _RGBA(255, 100, 255, 255)
  946.         CALL cprintstring(_HEIGHT / 2, "--Soft Array Editor--")
  947.         CALL cprintstring(-_HEIGHT / 2 + 16, "Press ESC to continue.")
  948.         COLOR _RGBA(255, 255, 255, 255)
  949.  
  950.         _DISPLAY
  951.  
  952.         _LIMIT 30
  953.     LOOP
  954.  
  955.  
  956. SUB Halt
  957.     _DELAY .01
  958.     _KEYCLEAR
  959.     COLOR _RGBA(255, 255, 100, 255)
  960.     PRINT "Press any key..."
  961.     COLOR _RGBA(255, 255, 255, 255)
  962.     _DISPLAY
  963.     DO: LOOP UNTIL INKEY$ <> ""
  964.     CLS
  965.     _DISPLAY
  966.  
  967. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  968. ' Visual Nodes
  969. '
  970.  
  971. SUB DefineVisualNode (i AS INTEGER, x AS LONG, cx AS DOUBLE, cy AS DOUBLE)
  972.     DIM h AS DOUBLE
  973.     DIM w AS DOUBLE
  974.     h = 22
  975.     w = 12 + 8 * LEN(Literal$(x))
  976.     VisualNodes(i).Reference = x
  977.     VisualNodes(i).BoxCenter.x = cx
  978.     VisualNodes(i).BoxCenter.y = cy
  979.     VisualNodes(i).BoxHeight = h
  980.     VisualNodes(i).BoxWidth = w
  981.     VisualNodes(i).CornerNE.x = cx + .5 * w
  982.     VisualNodes(i).CornerNE.y = cy + .5 * h
  983.     VisualNodes(i).CornerNW.x = cx - .5 * w
  984.     VisualNodes(i).CornerNW.y = cy + .5 * h
  985.     VisualNodes(i).CornerSE.x = cx + .5 * w
  986.     VisualNodes(i).CornerSE.y = cy - .5 * h
  987.     VisualNodes(i).CornerSW.x = cx - .5 * w
  988.     VisualNodes(i).CornerSW.y = cy - .5 * h
  989.     VisualNodes(i).AntennaN.x = cx
  990.     VisualNodes(i).AntennaN.y = cy + .5 * h + 3
  991.     VisualNodes(i).AntennaS.x = cx
  992.     VisualNodes(i).AntennaS.y = cy - .5 * h - 3
  993.     VisualNodes(i).AntennaE.x = cx + .5 * w + 3
  994.     VisualNodes(i).AntennaE.y = cy
  995.     VisualNodes(i).AntennaW.x = cx - .5 * w - 3
  996.     VisualNodes(i).AntennaW.y = cy
  997.  
  998. FUNCTION VisualNodeIndexFromReference (x AS LONG)
  999.     DIM TheReturn AS INTEGER
  1000.     DIM j AS INTEGER
  1001.     TheReturn = -1
  1002.     FOR j = 1 TO VisualNodesCount
  1003.         IF (VisualNodes(j).Reference = x) THEN
  1004.             TheReturn = j
  1005.             EXIT FOR
  1006.         END IF
  1007.     NEXT
  1008.     VisualNodeIndexFromReference = TheReturn
  1009.  
  1010. SUB BuildAllVisualArrays
  1011.     DIM k AS LONG
  1012.     DIM y0 AS DOUBLE
  1013.     VisualNodesCount = 0
  1014.     y0 = Origin.y + ScrollPosition.y
  1015.     FOR k = UBOUND(SoftArrayRegister) TO 1 STEP -1
  1016.         IF (SoftArrayRegister(k) <> -1) THEN
  1017.             CALL BuildVisualArray(SoftArray(k).HeadNode, Origin.x + ScrollPosition.x, y0)
  1018.             y0 = y0 - 30
  1019.         END IF
  1020.     NEXT
  1021.  
  1022. SUB BuildVisualArray (x AS LONG, x0 AS DOUBLE, y0 AS DOUBLE)
  1023.     DIM s AS LONG
  1024.     DIM e AS LONG
  1025.     DIM dxtmp AS DOUBLE
  1026.     s = Nodes(x).South
  1027.     e = Nodes(x).East
  1028.     VisualNodesCount = VisualNodesCount + 1
  1029.     CALL DefineVisualNode(VisualNodesCount, x, x0, y0)
  1030.     y0 = y0 - 30
  1031.     IF (e <> -1) THEN
  1032.         dxtmp = 8 * .5 * (LEN(Literal$(x)) + LEN(Literal$(e)))
  1033.         IF (dxtmp < 30) THEN dxtmp = 30
  1034.         CALL BuildVisualArray(e, x0 + dxtmp, y0)
  1035.     END IF
  1036.     IF (s <> -1) THEN
  1037.         CALL BuildVisualArray(s, x0, y0)
  1038.     END IF
  1039.  
  1040. SUB MoveAllVisualNodes (dx AS DOUBLE, dy AS DOUBLE)
  1041.     DIM k AS INTEGER
  1042.     FOR k = 1 TO VisualNodesCount
  1043.         CALL MoveSingleVisualNode(k, dx, dy)
  1044.     NEXT
  1045.  
  1046. SUB MoveVisualNodesRecur (i AS INTEGER, x AS LONG, dx AS DOUBLE, dy AS DOUBLE)
  1047.     DIM s AS LONG
  1048.     DIM e AS LONG
  1049.     DIM k AS INTEGER
  1050.     DIM f AS INTEGER
  1051.     s = Nodes(x).South
  1052.     e = Nodes(x).East
  1053.     IF (e <> -1) THEN
  1054.         f = 0
  1055.         FOR k = 1 TO VisualNodesCount
  1056.             IF (VisualNodes(k).Reference = e) THEN
  1057.                 f = 1
  1058.                 EXIT FOR
  1059.             END IF
  1060.         NEXT
  1061.         IF (f = 1) THEN
  1062.             CALL MoveVisualNodesRecur(k, e, dx, dy)
  1063.         END IF
  1064.     END IF
  1065.     IF (s <> -1) THEN
  1066.         f = 0
  1067.         FOR k = 1 TO VisualNodesCount
  1068.             IF (VisualNodes(k).Reference = s) THEN
  1069.                 f = 1
  1070.                 EXIT FOR
  1071.             END IF
  1072.         NEXT
  1073.         IF (f = 1) THEN
  1074.             CALL MoveVisualNodesRecur(k, s, dx, dy)
  1075.         END IF
  1076.     END IF
  1077.     CALL MoveSingleVisualNode(i, dx, dy)
  1078.  
  1079. SUB MoveSingleVisualNode (i AS INTEGER, dx AS DOUBLE, dy AS DOUBLE)
  1080.     CALL DefineVisualNode(i, VisualNodes(i).Reference, VisualNodes(i).BoxCenter.x + dx, VisualNodes(i).BoxCenter.y + dy)
  1081.  
  1082. SUB DrawAllVisualNodes (i AS INTEGER)
  1083.     DIM k AS INTEGER
  1084.     FOR k = 1 TO VisualNodesCount
  1085.         CALL DrawWiresSE(k)
  1086.         IF (i = 1) THEN
  1087.             CALL DrawWiresNW(k)
  1088.         END IF
  1089.         SELECT CASE Nodes(VisualNodes(k).Reference).Species
  1090.             CASE "integer"
  1091.                 CALL DrawSingleNode(k, _RGBA(255, 255, 255, 255), _RGBA(155, 55, 55, 255))
  1092.             CASE "text"
  1093.                 CALL DrawSingleNode(k, _RGBA(255, 255, 255, 255), _RGBA(55, 155, 55, 255))
  1094.             CASE "double"
  1095.                 CALL DrawSingleNode(k, _RGBA(255, 255, 255, 255), _RGBA(55, 55, 155, 255))
  1096.             CASE ELSE
  1097.                 CALL DrawSingleNode(k, _RGBA(255, 255, 255, 255), _RGBA(55, 55, 55, 255))
  1098.         END SELECT
  1099.     NEXT
  1100.  
  1101. SUB DrawSingleNode (x AS LONG, c1 AS _UNSIGNED LONG, c2 AS _UNSIGNED LONG)
  1102.     CALL clinebf(VisualNodes(x).CornerNE.x, VisualNodes(x).CornerNE.y, VisualNodes(x).CornerSW.x, VisualNodes(x).CornerSW.y, c2)
  1103.     COLOR c1, c2
  1104.     CALL bprintstring(VisualNodes(x).CornerNW.x + 6, VisualNodes(x).CornerNW.y - 4, Literal$(VisualNodes(x).Reference))
  1105.     CALL clineb(VisualNodes(x).CornerNE.x + 0, VisualNodes(x).CornerNE.y + 0, VisualNodes(x).CornerSW.x - 0, VisualNodes(x).CornerSW.y - 0, _RGB32(155, 155, 155, 255))
  1106.     COLOR _RGBA(255, 255, 255, 255), 0
  1107.  
  1108. SUB DrawWiresSE (x AS INTEGER)
  1109.     DIM i AS LONG
  1110.     DIM k AS INTEGER
  1111.     DIM s AS LONG
  1112.     DIM e AS LONG
  1113.     i = VisualNodes(x).Reference
  1114.     s = Nodes(i).South
  1115.     e = Nodes(i).East
  1116.     IF (s <> -1) THEN
  1117.         k = VisualNodeIndexFromReference(s)
  1118.         CALL cline(VisualNodes(x).AntennaS.x, VisualNodes(x).AntennaS.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGBA(155, 155, 155, 255))
  1119.         CALL ccircle(VisualNodes(x).AntennaS.x, VisualNodes(x).AntennaS.y, 3, _RGBA(155, 155, 155, 255))
  1120.     END IF
  1121.     IF (e <> -1) THEN
  1122.         k = VisualNodeIndexFromReference(e)
  1123.         CALL cline(VisualNodes(x).AntennaE.x, VisualNodes(x).AntennaE.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGBA(155, 155, 155, 255))
  1124.         CALL ccircle(VisualNodes(x).AntennaE.x, VisualNodes(x).AntennaE.y, 3, _RGBA(155, 155, 155, 255))
  1125.     END IF
  1126.  
  1127. SUB DrawWiresNW (x AS INTEGER)
  1128.     DIM i AS LONG
  1129.     DIM k AS INTEGER
  1130.     DIM n AS LONG
  1131.     DIM w AS LONG
  1132.     i = VisualNodes(x).Reference
  1133.     n = Nodes(i).North
  1134.     w = Nodes(i).West
  1135.     IF (n <> -1) THEN
  1136.         k = VisualNodeIndexFromReference(n)
  1137.         CALL cline(VisualNodes(x).AntennaN.x, VisualNodes(x).AntennaN.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGBA(255, 55, 55, 255))
  1138.         CALL ccircle(VisualNodes(x).AntennaN.x, VisualNodes(x).AntennaN.y, 3, _RGBA(255, 55, 55, 255))
  1139.     END IF
  1140.     IF (w <> -1) THEN
  1141.         k = VisualNodeIndexFromReference(w)
  1142.         CALL cline(VisualNodes(x).AntennaW.x, VisualNodes(x).AntennaW.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGBA(255, 55, 55, 255))
  1143.         CALL ccircle(VisualNodes(x).AntennaW.x, VisualNodes(x).AntennaW.y, 3, _RGBA(255, 55, 55, 255))
  1144.     END IF
  1145.  
  1146. FUNCTION MouseOver (x0 AS DOUBLE, y0 AS DOUBLE)
  1147.     DIM TheReturn AS INTEGER
  1148.     DIM k AS INTEGER
  1149.     TheReturn = -1
  1150.     FOR k = 1 TO VisualNodesCount
  1151.         IF (x0 > VisualNodes(k).BoxCenter.x - VisualNodes(k).BoxWidth / 2) AND (x0 < VisualNodes(k).BoxCenter.x + VisualNodes(k).BoxWidth / 2) THEN
  1152.             IF (y0 > VisualNodes(k).BoxCenter.y - VisualNodes(k).BoxHeight / 2) AND (y0 < VisualNodes(k).BoxCenter.y + VisualNodes(k).BoxHeight / 2) THEN
  1153.                 TheReturn = k
  1154.                 EXIT FOR
  1155.             END IF
  1156.         END IF
  1157.     NEXT
  1158.     MouseOver = TheReturn
  1159.  
  1160. SUB NewSelection (x AS INTEGER)
  1161.     DIM k AS INTEGER
  1162.     IF (SelectionIndex(1) <> x) THEN
  1163.         FOR k = UBOUND(SelectionIndex) TO 2 STEP -1
  1164.             SelectionIndex(k) = SelectionIndex(k - 1)
  1165.         NEXT
  1166.         SelectionIndex(1) = x
  1167.     END IF
  1168.  
  1169. FUNCTION ClearSelections (x AS INTEGER)
  1170.     DIM TheReturn AS INTEGER
  1171.     DIM k AS INTEGER
  1172.     FOR k = x TO UBOUND(SelectionIndex)
  1173.         SelectionIndex(k) = -1
  1174.     NEXT
  1175.     TheReturn = -1
  1176.     ClearSelections = TheReturn
  1177.  
  1178. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1179. ' Cartesian graphics
  1180. '
  1181.  
  1182. SUB cline (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  1183.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2, -y2 + _HEIGHT / 2), col
  1184.  
  1185. SUB clineb (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  1186.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2, -y2 + _HEIGHT / 2), col, B
  1187.  
  1188. SUB clinebf (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  1189.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2, -y2 + _HEIGHT / 2), col, BF
  1190.  
  1191. SUB ccircle (x1 AS DOUBLE, y1 AS DOUBLE, rad AS DOUBLE, col AS _UNSIGNED LONG)
  1192.     CIRCLE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), rad, col
  1193.  
  1194. SUB cpset (x1 AS DOUBLE, y1 AS DOUBLE, col AS _UNSIGNED LONG)
  1195.     PSET (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), col
  1196.  
  1197. SUB cpaint (x1 AS DOUBLE, y1 AS DOUBLE, col1 AS _UNSIGNED LONG, col2 AS _UNSIGNED LONG)
  1198.     PAINT (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), col1, col2
  1199.  
  1200. SUB bprintstring (x1 AS DOUBLE, y1 AS DOUBLE, a AS STRING)
  1201.     _PRINTSTRING (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), a
  1202.  
  1203. SUB cprintstring (y1 AS DOUBLE, a AS STRING)
  1204.     _PRINTSTRING (_WIDTH / 2 - (LEN(a) * 8) / 2, -y1 + _HEIGHT / 2), a
  1205.  
  1206. SUB lprintstring (x1 AS DOUBLE, y1 AS DOUBLE, a AS STRING)
  1207.     'LOCATE y1, x1: PRINT a
  1208.     _PRINTSTRING ((x1 - 1) * 8, (y1 - 1) * 16), a
  1209.  
  1210. SUB rprintstring (y1 AS DOUBLE, a AS STRING)
  1211.     _PRINTSTRING (_WIDTH - (LEN(a) * 8), (y1 - 1) * 16), a
  1212.  
  1213. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1214. ' End GUI/Graphical component (optional)
  1215. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1216.  
  1217. 'REM $Include: 'SoftArrays.bm'
  1218.  
  1219.  
  1220.  
  1221.  
  1222.  
  1223.  
  1224.  
  1225.  
  1226.  
  1227.  
  1228. 'REM $Include: 'SoftArrays.bi'
  1229.  
  1230. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1231. ' Begin BM-component.
  1232. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1233.  
  1234. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1235. ' Processing
  1236. '
  1237.  
  1238. FUNCTION EvalMultiSoftArrays (x AS INTEGER)
  1239.     DIM TheReturn AS LONG
  1240.     DIM k AS INTEGER
  1241.     FOR k = x TO UBOUND(SoftArrayRegister)
  1242.         IF (SoftArrayRegister(k) <> -1) THEN
  1243.             TheReturn = Evaluate(SoftArray(k).HeadNode)
  1244.         END IF
  1245.     NEXT
  1246.     EvalMultiSoftArrays = TheReturn
  1247.  
  1248. FUNCTION Evaluate (x AS LONG)
  1249.     DIM TheReturn AS LONG
  1250.     DIM a AS LONG
  1251.     DIM b AS LONG
  1252.     a = x
  1253.     b = -1
  1254.     DO
  1255.         a = EvalStep(FirstEmbedded(a))
  1256.         IF (a = x) THEN EXIT DO
  1257.         IF (a = b) THEN
  1258.             IF (a = -1) THEN EXIT DO
  1259.             a = Nodes(a).South
  1260.             IF (a = -1) THEN EXIT DO
  1261.         ELSE
  1262.             b = a
  1263.         END IF
  1264.     LOOP
  1265.     TheReturn = a
  1266.     Evaluate = TheReturn
  1267.  
  1268. FUNCTION EvalStep (x AS LONG)
  1269.     DIM TheReturn AS LONG
  1270.     DIM SouthernId AS LONG
  1271.     DIM NorthernId AS LONG
  1272.     DIM FunctionId AS LONG
  1273.     DIM i AS LONG
  1274.     DIM j AS LONG
  1275.     DIM k AS INTEGER
  1276.     DIM n AS LONG
  1277.     DIM s AS LONG
  1278.     DIM RefSpecies AS STRING
  1279.     DIM ReturnSpecies AS STRING
  1280.     DIM ReturnInteger AS INTEGER
  1281.     DIM ReturnText AS STRING
  1282.     DIM ReturnDouble AS DOUBLE
  1283.     DIM MultiPass AS INTEGER
  1284.  
  1285.     RefSpecies = ""
  1286.     FunctionId = x
  1287.     ReturnSpecies = ""
  1288.     ReturnInteger = 0
  1289.     ReturnText = ""
  1290.     ReturnDouble = 0
  1291.  
  1292.     ' Pre-evaluation
  1293.     IF (x <> -1) THEN
  1294.         SouthernId = x
  1295.         i = x
  1296.         DO
  1297.             n = Nodes(i).North
  1298.             IF (n <> -1) THEN
  1299.                 i = n
  1300.             ELSE
  1301.                 NorthernId = i
  1302.                 EXIT DO
  1303.             END IF
  1304.         LOOP
  1305.         FunctionId = Nodes(NorthernId).West
  1306.         IF (FunctionId <> -1) THEN
  1307.             ReturnSpecies = Nodes(FunctionId).Species
  1308.             SELECT CASE ReturnSpecies
  1309.                 CASE "integer"
  1310.                     ReturnInteger = IntegerData(Nodes(FunctionId).Reference)
  1311.                 CASE "text"
  1312.                     ReturnText = TextData(Nodes(FunctionId).Reference)
  1313.                 CASE "double"
  1314.                     ReturnDouble = DoubleData(Nodes(FunctionId).Reference)
  1315.             END SELECT
  1316.         END IF
  1317.     END IF
  1318.  
  1319.     ' Lambda substitution
  1320.     i = NorthernId
  1321.     DIM lf AS INTEGER
  1322.     lf = 0
  1323.     DO
  1324.         IF (Nodes(i).Species = "text") THEN
  1325.             IF (TextData(Nodes(i).Reference) = "[1]") THEN
  1326.                 j = LambdaMatrix(LambdaIndex, 1)
  1327.                 Nodes(i).Species = Nodes(j).Species
  1328.                 Nodes(i).Reference = Nodes(j).Reference
  1329.                 lf = 1
  1330.             END IF
  1331.             IF (TextData(Nodes(i).Reference) = "[2]") THEN
  1332.                 j = LambdaMatrix(LambdaIndex, 2)
  1333.                 Nodes(i).Species = Nodes(j).Species
  1334.                 Nodes(i).Reference = Nodes(j).Reference
  1335.                 lf = 1
  1336.             END IF
  1337.         END IF
  1338.         IF (i = SouthernId) THEN
  1339.             EXIT DO
  1340.         ELSE
  1341.             s = Nodes(i).South
  1342.             i = s
  1343.         END IF
  1344.     LOOP
  1345.     IF (lf = 1) THEN
  1346.         FOR k = 1 TO LambdaArgCount(LambdaIndex)
  1347.             j = Unlink(LambdaMatrix(LambdaIndex, k))
  1348.         NEXT
  1349.         LambdaArgCount(LambdaIndex) = 0
  1350.         LambdaIndex = LambdaIndex - 1
  1351.     END IF
  1352.  
  1353.     ' Determine return species
  1354.     i = NorthernId
  1355.     DO
  1356.         IF (i = -1) THEN EXIT DO
  1357.         IF (Nodes(i).Species = "text") THEN RefSpecies = "text"
  1358.         IF ((Nodes(i).Species = "double") AND (RefSpecies <> "text")) THEN RefSpecies = "double"
  1359.         IF ((Nodes(i).Species = "integer") AND (RefSpecies <> "text") AND (RefSpecies <> "double")) THEN RefSpecies = "integer"
  1360.         i = Nodes(i).South
  1361.     LOOP
  1362.  
  1363.     ' Single-pass evaluation
  1364.     MultiPass = 0
  1365.     SELECT CASE Literal$(FunctionId)
  1366.         CASE "*"
  1367.             MultiPass = 1
  1368.             ReturnSpecies = RefSpecies
  1369.             ReturnInteger = 1
  1370.             ReturnDouble = 1
  1371.         CASE "+"
  1372.             MultiPass = 1
  1373.             ReturnSpecies = RefSpecies
  1374.             ReturnInteger = 0
  1375.             ReturnDouble = 0
  1376.         CASE "/"
  1377.             MultiPass = 0
  1378.             SELECT CASE Nodes(NorthernId).Species
  1379.                 CASE "integer"
  1380.                     ReturnSpecies = "double"
  1381.                     SELECT CASE Nodes(SouthernId).Species
  1382.                         CASE "integer"
  1383.                             ReturnDouble = IntegerData(Nodes(NorthernId).Reference) / IntegerData(Nodes(SouthernId).Reference)
  1384.                         CASE "double"
  1385.                             ReturnDouble = IntegerData(Nodes(NorthernId).Reference) / DoubleData(Nodes(SouthernId).Reference)
  1386.                     END SELECT
  1387.                 CASE "text"
  1388.                     ReturnSpecies = "text"
  1389.                     ReturnText = Literal$(NorthernId) + "/" + Literal$(SouthernId)
  1390.                 CASE "double"
  1391.                     ReturnSpecies = "double"
  1392.                     SELECT CASE Nodes(SouthernId).Species
  1393.                         CASE "integer"
  1394.                             ReturnDouble = DoubleData(Nodes(NorthernId).Reference) / IntegerData(Nodes(SouthernId).Reference)
  1395.                         CASE "double"
  1396.                             ReturnDouble = DoubleData(Nodes(NorthernId).Reference) / DoubleData(Nodes(SouthernId).Reference)
  1397.                     END SELECT
  1398.             END SELECT
  1399.             i = Unlink(NorthernId)
  1400.             i = Unlink(SouthernId)
  1401.         CASE "cos"
  1402.             IF (NorthernId = SouthernId) THEN
  1403.                 MultiPass = 0
  1404.                 i = NorthernId
  1405.                 SELECT CASE Nodes(i).Species
  1406.                     CASE "integer"
  1407.                         ReturnSpecies = "double"
  1408.                         ReturnDouble = COS(IntegerData(Nodes(i).Reference))
  1409.                     CASE "text"
  1410.                         ReturnSpecies = "text"
  1411.                         ReturnText = "cos" + "(" + Literal$(i) + ")"
  1412.                     CASE "double"
  1413.                         ReturnSpecies = "double"
  1414.                         ReturnDouble = COS(DoubleData(Nodes(i).Reference))
  1415.                 END SELECT
  1416.                 i = Unlink(i)
  1417.             ELSE
  1418.                 MultiPass = 1
  1419.                 ReturnSpecies = "text"
  1420.                 ReturnText = "(" + "cos" + ")"
  1421.             END IF
  1422.         CASE "lambda"
  1423.             MultiPass = 1
  1424.             LambdaIndex = LambdaIndex + 1
  1425.             ReturnSpecies = "text"
  1426.             ReturnText = "(" + "lambda" + ")"
  1427.         CASE "(" + "lambda" + ")"
  1428.             '
  1429.     END SELECT
  1430.  
  1431.     ' Multi-pass evaluation
  1432.     IF (MultiPass = 1) THEN
  1433.         i = NorthernId
  1434.         DO
  1435.             SELECT CASE Literal$(FunctionId)
  1436.                 CASE "*"
  1437.                     SELECT CASE ReturnSpecies
  1438.                         CASE "integer"
  1439.                             SELECT CASE Nodes(i).Species
  1440.                                 CASE "integer"
  1441.                                     ReturnInteger = ReturnInteger * IntegerData(Nodes(i).Reference)
  1442.                                 CASE "double"
  1443.                                     ReturnInteger = ReturnInteger * DoubleData(Nodes(i).Reference)
  1444.                             END SELECT
  1445.                         CASE "text"
  1446.                             ReturnText = ReturnText + Literal$(i)
  1447.                         CASE "double"
  1448.                             SELECT CASE Nodes(i).Species
  1449.                                 CASE "integer"
  1450.                                     ReturnDouble = ReturnDouble * IntegerData(Nodes(i).Reference)
  1451.                                 CASE "double"
  1452.                                     ReturnDouble = ReturnDouble * DoubleData(Nodes(i).Reference)
  1453.                             END SELECT
  1454.                     END SELECT
  1455.                     IF (i = SouthernId) THEN
  1456.                         i = Unlink(i)
  1457.                         EXIT DO
  1458.                     ELSE
  1459.                         s = Nodes(i).South
  1460.                         i = Unlink(i)
  1461.                         i = s
  1462.                     END IF
  1463.                 CASE "+"
  1464.                     SELECT CASE ReturnSpecies
  1465.                         CASE "integer"
  1466.                             SELECT CASE Nodes(i).Species
  1467.                                 CASE "integer"
  1468.                                     ReturnInteger = ReturnInteger + IntegerData(Nodes(i).Reference)
  1469.                                 CASE "double"
  1470.                                     ReturnInteger = ReturnInteger + DoubleData(Nodes(i).Reference)
  1471.                             END SELECT
  1472.                         CASE "text"
  1473.                             ReturnText = ReturnText + Literal$(i)
  1474.                         CASE "double"
  1475.                             SELECT CASE Nodes(i).Species
  1476.                                 CASE "integer"
  1477.                                     ReturnDouble = ReturnDouble + IntegerData(Nodes(i).Reference)
  1478.                                 CASE "double"
  1479.                                     ReturnDouble = ReturnDouble + DoubleData(Nodes(i).Reference)
  1480.                             END SELECT
  1481.                     END SELECT
  1482.                     IF (i = SouthernId) THEN
  1483.                         i = Unlink(i)
  1484.                         EXIT DO
  1485.                     ELSE
  1486.                         s = Nodes(i).South
  1487.                         i = Unlink(i)
  1488.                         i = s
  1489.                     END IF
  1490.                 CASE "cos"
  1491.                     SELECT CASE Nodes(i).Species
  1492.                         CASE "integer"
  1493.                             Nodes(i).Species = "double"
  1494.                             Nodes(i).Reference = NewDoubleData(COS(IntegerData(Nodes(i).Reference)))
  1495.                         CASE "text"
  1496.                             Nodes(i).Reference = NewTextData("cos" + "(" + Literal$(i) + ")")
  1497.                         CASE "double"
  1498.                             Nodes(i).Species = "double"
  1499.                             Nodes(i).Reference = NewDoubleData(COS(DoubleData(Nodes(i).Reference)))
  1500.                     END SELECT
  1501.                     IF (i = SouthernId) THEN
  1502.                         EXIT DO
  1503.                     ELSE
  1504.                         s = Nodes(i).South
  1505.                         i = s
  1506.                     END IF
  1507.                 CASE "lambda"
  1508.                     LambdaArgCount(LambdaIndex) = LambdaArgCount(LambdaIndex) + 1
  1509.                     LambdaMatrix(LambdaIndex, LambdaArgCount(LambdaIndex)) = i
  1510.                     IF (i = SouthernId) THEN
  1511.                         EXIT DO
  1512.                     ELSE
  1513.                         s = Nodes(i).South
  1514.                         i = s
  1515.                     END IF
  1516.             END SELECT
  1517.         LOOP
  1518.     END IF
  1519.  
  1520.     SELECT CASE ReturnSpecies
  1521.         CASE "integer"
  1522.             Nodes(FunctionId).Species = ReturnSpecies
  1523.             Nodes(FunctionId).Reference = NewIntegerData(ReturnInteger)
  1524.         CASE "text"
  1525.             Nodes(FunctionId).Species = ReturnSpecies
  1526.             Nodes(FunctionId).Reference = NewTextData(ReturnText)
  1527.         CASE "double"
  1528.             Nodes(FunctionId).Species = ReturnSpecies
  1529.             Nodes(FunctionId).Reference = NewDoubleData(ReturnDouble)
  1530.     END SELECT
  1531.  
  1532.     TheReturn = FunctionId
  1533.     EvalStep = TheReturn
  1534.  
  1535. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1536. ' Eval helper functions
  1537. '
  1538.  
  1539. FUNCTION FirstEmbedded (x AS LONG)
  1540.     DIM TheReturn AS LONG
  1541.     TheReturn = MostEmbeddedRecur(x, -1)
  1542.     FirstEmbedded = TheReturn
  1543.  
  1544. FUNCTION MostEmbeddedRecur (x AS LONG, y AS LONG)
  1545.     DIM TheReturn AS LONG
  1546.     DIM s AS LONG
  1547.     DIM e AS LONG
  1548.     s = Nodes(x).South
  1549.     e = Nodes(x).East
  1550.     IF (e <> -1) THEN
  1551.         TheReturn = MostEmbeddedRecur(e, y)
  1552.     END IF
  1553.     IF (s <> -1) THEN
  1554.         TheReturn = MostEmbeddedRecur(s, y)
  1555.     END IF
  1556.     IF ((e = -1) AND (s = -1) AND (y = -1)) THEN
  1557.         y = x
  1558.     END IF
  1559.     TheReturn = y
  1560.     MostEmbeddedRecur = TheReturn
  1561.  
  1562. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1563. ' Programmer-friendly functions
  1564. '
  1565.  
  1566. FUNCTION SoftArrayID (t AS STRING)
  1567.     '
  1568.     ' Inputs a soft array label and returns the node address.
  1569.     '
  1570.     DIM TheReturn AS LONG
  1571.     DIM k AS LONG
  1572.     TheReturn = -1
  1573.     FOR k = 1 TO UBOUND(SoftArray)
  1574.         IF (SoftArray(k).Label = t) THEN
  1575.             TheReturn = k
  1576.             EXIT FOR
  1577.         END IF
  1578.     NEXT
  1579.     SoftArrayID = TheReturn
  1580.  
  1581. FUNCTION SeekText (t AS STRING, x AS LONG, r AS INTEGER)
  1582.     DIM TheReturn AS LONG
  1583.     DIM s AS LONG
  1584.     DIM e AS LONG
  1585.     TheReturn = -1
  1586.     s = Nodes(x).South
  1587.     e = Nodes(x).East
  1588.     IF (TextData(Nodes(x).Reference) = t) THEN
  1589.         TheReturn = x
  1590.         r = r - 1
  1591.     ELSE
  1592.         IF ((e <> -1) AND (r > 0)) THEN
  1593.             TheReturn = SeekText(t, e, r)
  1594.         END IF
  1595.         IF ((s <> -1) AND (r > 0)) THEN
  1596.             TheReturn = SeekText(t, s, r)
  1597.         END IF
  1598.     END IF
  1599.     SeekText = TheReturn
  1600.  
  1601. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1602. ' Navigation
  1603. '
  1604. FUNCTION JumpFrom (x AS LONG, t AS STRING, r AS INTEGER)
  1605.     DIM TheReturn AS LONG
  1606.     TheReturn = x
  1607.     IF (r > 0) THEN
  1608.         SELECT CASE t
  1609.             CASE "n"
  1610.                 TheReturn = JumpFrom(Nodes(x).North, "n", r - 1)
  1611.             CASE "s"
  1612.                 TheReturn = JumpFrom(Nodes(x).South, "s", r - 1)
  1613.             CASE "e"
  1614.                 TheReturn = JumpFrom(Nodes(x).East, "e", r - 1)
  1615.             CASE "w"
  1616.                 TheReturn = JumpFrom(Nodes(x).West, "w", r - 1)
  1617.         END SELECT
  1618.     END IF
  1619.     JumpFrom = TheReturn
  1620.  
  1621. FUNCTION StepFromUsing (x AS LONG, t AS STRING)
  1622.     DIM TheReturn AS LONG
  1623.     DIM i AS LONG
  1624.     DIM j AS LONG
  1625.     DIM k AS INTEGER
  1626.     i = x
  1627.     FOR k = 1 TO LEN(t)
  1628.         SELECT CASE MID$(t, k, 1)
  1629.             CASE "n"
  1630.                 j = Nodes(i).North
  1631.                 IF (j <> -1) THEN i = j
  1632.             CASE "s"
  1633.                 j = Nodes(i).South
  1634.                 IF (j <> -1) THEN i = j
  1635.             CASE "e"
  1636.                 j = Nodes(i).East
  1637.                 IF (j <> -1) THEN i = j
  1638.             CASE "w"
  1639.                 j = Nodes(i).West
  1640.                 IF (j <> -1) THEN i = j
  1641.         END SELECT
  1642.     NEXT
  1643.     TheReturn = i
  1644.     StepFromUsing = TheReturn
  1645.  
  1646. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1647. ' Internal metrics
  1648. '
  1649. FUNCTION Measure (x AS LONG, t AS STRING)
  1650.     '
  1651.     ' A simpler version of CountSteps that looks for -1.
  1652.     '
  1653.     DIM TheReturn AS INTEGER
  1654.     TheReturn = CountSteps(x, -1, t)
  1655.     Measure = TheReturn
  1656.  
  1657. FUNCTION CountSteps (x AS LONG, y AS LONG, t AS STRING)
  1658.     DIM TheReturn AS INTEGER
  1659.     DIM k AS LONG
  1660.     TheReturn = 0
  1661.     SELECT CASE t
  1662.         CASE "n"
  1663.             k = Nodes(x).North
  1664.         CASE "s"
  1665.             k = Nodes(x).South
  1666.         CASE "e"
  1667.             k = Nodes(x).East
  1668.         CASE "w"
  1669.             k = Nodes(x).West
  1670.     END SELECT
  1671.     IF (k = y) THEN
  1672.         TheReturn = TheReturn + 1
  1673.     ELSE
  1674.         IF (k <> -1) THEN
  1675.             TheReturn = TheReturn + 1 + CountSteps(k, y, t)
  1676.         END IF
  1677.     END IF
  1678.     CountSteps = TheReturn
  1679.  
  1680. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1681. ' Printing and Reporting
  1682. '
  1683.  
  1684. FUNCTION PrintJSON$ (x AS LONG)
  1685.     DIM TheReturn AS STRING
  1686.     DIM t AS STRING
  1687.     't = Literal$(x) + " = {" + CHR$(10) + WriteJSONRecur$(1, Nodes(x).East) + "}"
  1688.     t = "{" + CHR$(10) + WriteJSONRecur$(0, Nodes(x).East) + "}"
  1689.     TheReturn = t
  1690.     PrintJSON$ = TheReturn
  1691.  
  1692. FUNCTION WriteJSONRecur$ (i AS INTEGER, x AS LONG)
  1693.     DIM TheReturn AS STRING
  1694.     DIM ThisLiteral AS STRING
  1695.     DIM n AS LONG
  1696.     DIM s AS LONG
  1697.     DIM e AS LONG
  1698.     DIM w AS LONG
  1699.     DIM lb AS STRING
  1700.     DIM rb AS STRING
  1701.     DIM lq AS STRING
  1702.     DIM rq AS STRING
  1703.  
  1704.     ThisLiteral = LiteralJSON$(x)
  1705.     n = Nodes(x).North
  1706.     s = Nodes(x).South
  1707.     e = Nodes(x).East
  1708.     w = Nodes(x).West
  1709.     lb = ""
  1710.     rb = ""
  1711.     lq = ""
  1712.     rq = ""
  1713.  
  1714.     IF (Literal$(x) = "[]") THEN
  1715.         lb = "["
  1716.         rb = Filler$(i, "  ") + "]" + CHR$(10)
  1717.         ThisLiteral = lb
  1718.     END IF
  1719.  
  1720.     IF (Literal$(x) = "{}") THEN
  1721.         lq = "{"
  1722.         rq = Filler$(i, "  ") + "}"
  1723.         ThisLiteral = lq
  1724.         IF (s <> -1) THEN rq = rq + ","
  1725.         rq = rq + CHR$(10)
  1726.     END IF
  1727.  
  1728.     ThisLiteral = Filler$(i, "  ") + ThisLiteral
  1729.  
  1730.     IF (e <> -1) THEN
  1731.         IF (Nodes(e).East = -1) THEN ThisLiteral = ThisLiteral + ":"
  1732.     END IF
  1733.     IF (n <> -1) AND (s <> -1) AND (e = -1) AND (w = -1) THEN ThisLiteral = ThisLiteral + ","
  1734.     IF (n = -1) AND (s = -1) AND (e = -1) AND (w <> -1) THEN ThisLiteral = ThisLiteral + ","
  1735.  
  1736.     TheReturn = TheReturn + ThisLiteral + CHR$(10)
  1737.  
  1738.     IF (e <> -1) THEN
  1739.         TheReturn = TheReturn + WriteJSONRecur$(i + 1, e) + rq
  1740.     END IF
  1741.     IF (s <> -1) THEN
  1742.         TheReturn = TheReturn + WriteJSONRecur$(i, s) + rb
  1743.     END IF
  1744.  
  1745.     WriteJSONRecur$ = TheReturn
  1746.  
  1747. FUNCTION MemoryProbe$ (t AS STRING)
  1748.     DIM TheReturn AS STRING
  1749.     DIM a AS LONG
  1750.     DIM k AS INTEGER
  1751.     TheReturn = t
  1752.     TheReturn = TheReturn + "Begin memory probe..." + CHR$(10)
  1753.     TheReturn = TheReturn + "Soft arrays:" + CHR$(10)
  1754.     FOR k = 1 TO UBOUND(SoftArrayRegister)
  1755.         IF (SoftArrayRegister(k) <> -1) THEN
  1756.             TheReturn = TheReturn + "  " + SoftArray(k).Label + " (@@" + STR$(SoftArrayRegister(k)) + ") (@" + STR$(SoftArray(k).HeadNode) + ")" + CHR$(10)
  1757.         END IF
  1758.     NEXT
  1759.     TheReturn = TheReturn + "Nodes:" + CHR$(10)
  1760.     FOR k = 1 TO UBOUND(IdentityRegister)
  1761.         IF (IdentityRegister(k) <> -1) THEN
  1762.             a = IdentityRegister(k)
  1763.             TheReturn = TheReturn + "  " + Literal$(a)
  1764.             TheReturn = TheReturn + " (@" + STR$(IdentityRegister(k)) + ")"
  1765.             TheReturn = TheReturn + " (" + LTRIM$(RTRIM$(STR$(Nodes(a).North))) + "," + LTRIM$(RTRIM$(STR$(Nodes(a).South))) + "," + LTRIM$(RTRIM$(STR$(Nodes(a).East))) + "," + LTRIM$(RTRIM$(STR$(Nodes(a).West))) + ")"
  1766.             TheReturn = TheReturn + CHR$(10)
  1767.         END IF
  1768.     NEXT
  1769.     TheReturn = TheReturn + "End memory probe..." + CHR$(10)
  1770.     MemoryProbe$ = TheReturn
  1771.  
  1772. FUNCTION PrintMultiSoftArrays$ (x AS INTEGER)
  1773.     DIM TheReturn AS STRING
  1774.     DIM k AS INTEGER
  1775.     TheReturn = ""
  1776.     FOR k = x TO UBOUND(SoftArrayRegister)
  1777.         IF (SoftArrayRegister(k) <> -1) THEN
  1778.             TheReturn = TheReturn + PrintSoftArray$(SoftArray(k).HeadNode)
  1779.             IF (x < UBOUND(SoftArrayRegister)) THEN
  1780.                 TheReturn = TheReturn + CHR$(10)
  1781.             END IF
  1782.         END IF
  1783.     NEXT
  1784.     PrintMultiSoftArrays$ = TheReturn
  1785.  
  1786. FUNCTION PrintSoftArray$ (x AS LONG)
  1787.     DIM TheReturn AS STRING
  1788.     DIM t AS STRING
  1789.     t = ListNodesRecur$(0, x)
  1790.     TheReturn = LEFT$(t, LEN(t) - 1)
  1791.     PrintSoftArray$ = TheReturn
  1792.  
  1793. FUNCTION ListNodesRecur$ (i AS INTEGER, x AS LONG)
  1794.     DIM TheReturn AS STRING
  1795.     DIM s AS LONG
  1796.     DIM e AS LONG
  1797.     s = Nodes(x).South
  1798.     e = Nodes(x).East
  1799.     TheReturn = TheReturn + Filler$(i, "  ") + Literal$(x) 'CHR$(9)
  1800.     'TheReturn = TheReturn  + " (" + STR$(Nodes(x).North) + "," + STR$(Nodes(x).South) + "," + STR$(Nodes(x).East) + "," + STR$(Nodes(x).West) + ")"
  1801.     TheReturn = TheReturn + CHR$(10)
  1802.     IF (e <> -1) THEN
  1803.         TheReturn = TheReturn + ListNodesRecur$(i + 1, e)
  1804.     END IF
  1805.     IF (s <> -1) THEN
  1806.         TheReturn = TheReturn + ListNodesRecur$(i, s)
  1807.     END IF
  1808.     ListNodesRecur$ = TheReturn
  1809.  
  1810. FUNCTION IdentityStackBuildRecur (x AS LONG, r AS INTEGER)
  1811.     DIM TheReturn AS LONG
  1812.     DIM n AS LONG
  1813.     DIM s AS LONG
  1814.     DIM e AS LONG
  1815.     DIM w AS LONG
  1816.     n = Nodes(x).North
  1817.     s = Nodes(x).South
  1818.     e = Nodes(x).East
  1819.     w = Nodes(x).West
  1820.     IdentityStackSize = IdentityStackSize + 1
  1821.     IdentityStack(IdentityStackSize, 1) = x
  1822.     IdentityStack(IdentityStackSize, 2) = n
  1823.     IdentityStack(IdentityStackSize, 3) = s
  1824.     IdentityStack(IdentityStackSize, 4) = e
  1825.     IdentityStack(IdentityStackSize, 5) = w
  1826.     IF (r <> -1) THEN
  1827.         IF (e <> -1) THEN
  1828.             TheReturn = IdentityStackBuildRecur(e, 1)
  1829.         END IF
  1830.         IF (r <> 0) THEN
  1831.             IF (s <> -1) THEN
  1832.                 TheReturn = IdentityStackBuildRecur(s, 1)
  1833.             END IF
  1834.         END IF
  1835.     ELSE
  1836.         TheReturn = -1
  1837.     END IF
  1838.     IdentityStackBuildRecur = TheReturn
  1839.  
  1840. FUNCTION Literal$ (x AS LONG)
  1841.     DIM TheReturn AS STRING
  1842.     TheReturn = ""
  1843.     IF (x <> -1) THEN
  1844.         SELECT CASE Nodes(x).Species
  1845.             CASE "integer"
  1846.                 TheReturn = LTRIM$(RTRIM$(STR$(IntegerData(Nodes(x).Reference))))
  1847.             CASE "text"
  1848.                 TheReturn = TextData(Nodes(x).Reference)
  1849.             CASE "double"
  1850.                 TheReturn = LTRIM$(RTRIM$(STR$(DoubleData(Nodes(x).Reference))))
  1851.         END SELECT
  1852.     END IF
  1853.     Literal$ = TheReturn
  1854.  
  1855. FUNCTION LiteralJSON$ (x AS LONG)
  1856.     DIM TheReturn AS STRING
  1857.     TheReturn = ""
  1858.     IF (x <> -1) THEN
  1859.         SELECT CASE Nodes(x).Species
  1860.             CASE "integer"
  1861.                 TheReturn = LTRIM$(RTRIM$(STR$(IntegerData(Nodes(x).Reference))))
  1862.             CASE "text"
  1863.                 TheReturn = CHR$(34) + TextData(Nodes(x).Reference) + CHR$(34)
  1864.             CASE "double"
  1865.                 TheReturn = LTRIM$(RTRIM$(STR$(DoubleData(Nodes(x).Reference))))
  1866.         END SELECT
  1867.     END IF
  1868.     LiteralJSON$ = TheReturn
  1869.  
  1870.  
  1871. FUNCTION Filler$ (x AS INTEGER, t AS STRING)
  1872.     DIM TheReturn AS STRING
  1873.     DIM k AS INTEGER
  1874.     IF (x > 0) THEN
  1875.         FOR k = 1 TO x
  1876.             TheReturn = TheReturn + t
  1877.         NEXT
  1878.     ELSE
  1879.         TheReturn = ""
  1880.     END IF
  1881.     Filler$ = TheReturn
  1882.  
  1883. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1884. ' Soft array construction
  1885. '
  1886.  
  1887. FUNCTION NewUnitArray (t AS STRING, x AS LONG)
  1888.     DIM TheReturn AS LONG
  1889.     DIM k AS LONG
  1890.     DIM r AS LONG
  1891.     r = NewSoftArray(t)
  1892.     TheReturn = r
  1893.     k = LinkEast(TheReturn, x)
  1894.     NewUnitArray = TheReturn
  1895.  
  1896. FUNCTION NewSoftArray (t AS STRING)
  1897.     DIM TheReturn AS LONG
  1898.     DIM i AS LONG
  1899.     TheReturn = NewTextNode(t)
  1900.     i = NextOpenSoftArray(1)
  1901.     SoftArrayRegister(i) = i
  1902.     SoftArray(i).Label = TextData(Nodes(TheReturn).Reference)
  1903.     SoftArray(i).HeadNode = TheReturn
  1904.     NewSoftArray = TheReturn
  1905.  
  1906. FUNCTION NextOpenSoftArray (x AS LONG)
  1907.     DIM TheReturn AS LONG
  1908.     DIM k AS LONG
  1909.     TheReturn = -1
  1910.     FOR k = x TO UBOUND(SoftArrayRegister)
  1911.         IF (SoftArrayRegister(k) = -1) THEN
  1912.             TheReturn = k
  1913.             EXIT FOR
  1914.         END IF
  1915.     NEXT
  1916.     NextOpenSoftArray = TheReturn
  1917.  
  1918. FUNCTION LinkSouth (n AS LONG, s AS LONG)
  1919.     DIM TheReturn AS LONG
  1920.     Nodes(s).North = n
  1921.     Nodes(n).South = s
  1922.     TheReturn = s
  1923.     LinkSouth = TheReturn
  1924.  
  1925. FUNCTION LinkEast (w AS LONG, e AS LONG)
  1926.     DIM TheReturn AS LONG
  1927.     Nodes(w).East = e
  1928.     Nodes(e).West = w
  1929.     TheReturn = e
  1930.     LinkEast = TheReturn
  1931.  
  1932. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1933. ' Soft array editing
  1934. '
  1935.  
  1936. FUNCTION InsertSouth (n AS LONG, x AS LONG)
  1937.     DIM s AS LONG
  1938.     s = Nodes(n).South
  1939.     Nodes(n).South = x
  1940.     Nodes(x).North = n
  1941.     Nodes(x).South = s
  1942.     IF (s <> -1) THEN
  1943.         Nodes(s).North = x
  1944.     END IF
  1945.     InsertSouth = x
  1946.  
  1947. FUNCTION InsertEast (w AS LONG, x AS LONG)
  1948.     DIM e AS LONG
  1949.     e = Nodes(w).East
  1950.     Nodes(w).East = x
  1951.     Nodes(x).West = w
  1952.     Nodes(x).East = e
  1953.     IF (e <> -1) THEN
  1954.         Nodes(e).West = x
  1955.     END IF
  1956.     InsertEast = x
  1957.  
  1958. FUNCTION Unlink (x AS LONG)
  1959.     DIM n AS LONG
  1960.     DIM s AS LONG
  1961.     DIM e AS LONG
  1962.     DIM w AS LONG
  1963.     DIM k AS INTEGER
  1964.     n = Nodes(x).North
  1965.     s = Nodes(x).South
  1966.     e = Nodes(x).East
  1967.     w = Nodes(x).West
  1968.     IF (n = -1) AND (s = -1) AND (w = -1) THEN ' head node
  1969.         FOR k = 1 TO UBOUND(SoftArrayRegister)
  1970.             IF (SoftArray(k).HeadNode = x) THEN
  1971.                 SoftArrayRegister(k) = -1
  1972.             END IF
  1973.         NEXT
  1974.     END IF
  1975.     IF (n <> -1) THEN Nodes(n).South = s
  1976.     IF (s <> -1) THEN Nodes(s).North = n
  1977.     IF (e <> -1) THEN Nodes(e).West = w
  1978.     IF (w <> -1) THEN Nodes(w).East = e
  1979.     IF ((n = -1) AND (w <> -1)) THEN ' content node
  1980.         IF (s <> -1) THEN
  1981.             Nodes(s).West = w
  1982.             Nodes(s).North = -1
  1983.             Nodes(w).East = s
  1984.         END IF
  1985.     END IF
  1986.     IdentityRegister(x) = -1
  1987.     Unlink = x
  1988.  
  1989. FUNCTION DeleteNodes (x AS LONG)
  1990.     DIM TheReturn AS LONG
  1991.     DIM e AS LONG
  1992.     e = Nodes(x).East
  1993.     IF (e <> -1) THEN
  1994.         TheReturn = DeleteNodesRecur(e)
  1995.     END IF
  1996.     TheReturn = Unlink(x)
  1997.     DeleteNodes = TheReturn
  1998.  
  1999. FUNCTION DeleteNodesRecur (x AS LONG)
  2000.     DIM TheReturn AS LONG
  2001.     DIM s AS LONG
  2002.     DIM e AS LONG
  2003.     s = Nodes(x).South
  2004.     e = Nodes(x).East
  2005.     IF (e <> -1) THEN
  2006.         TheReturn = DeleteNodesRecur(e)
  2007.     END IF
  2008.     IF (s <> -1) THEN
  2009.         TheReturn = DeleteNodesRecur(s)
  2010.     END IF
  2011.     TheReturn = Unlink(x)
  2012.     DeleteNodesRecur = TheReturn
  2013.  
  2014. FUNCTION CopyNodes (x AS LONG)
  2015.     DIM TheReturn AS LONG
  2016.     DIM k AS INTEGER
  2017.     DIM j AS INTEGER
  2018.     DIM n AS INTEGER
  2019.     DIM i AS INTEGER
  2020.     DIM m AS INTEGER
  2021.     DIM a AS LONG
  2022.     DIM b AS LONG
  2023.     a = IdentityStackBuildRecur(x, 0)
  2024.     FOR k = 1 TO IdentityStackSize
  2025.         i = k + IdentityStackSize
  2026.         a = NewNode(NextOpenIdentity(IdentityStack(k, 1)), Nodes(IdentityStack(k, 1)).Species, Nodes(IdentityStack(k, 1)).Reference)
  2027.         IdentityStack(i, 1) = a
  2028.     NEXT
  2029.     FOR k = 1 TO IdentityStackSize
  2030.         i = k + IdentityStackSize
  2031.         FOR j = 2 TO 5
  2032.             a = IdentityStack(k, j)
  2033.             FOR n = 1 TO IdentityStackSize
  2034.                 m = n + IdentityStackSize
  2035.                 b = IdentityStack(n, 1)
  2036.                 IF (b = a) THEN
  2037.                     SELECT CASE j
  2038.                         CASE 2
  2039.                             Nodes(IdentityStack(i, 1)).North = IdentityStack(m, 1)
  2040.                         CASE 3
  2041.                             Nodes(IdentityStack(i, 1)).South = IdentityStack(m, 1)
  2042.                         CASE 4
  2043.                             Nodes(IdentityStack(i, 1)).East = IdentityStack(m, 1)
  2044.                         CASE 5
  2045.                             Nodes(IdentityStack(i, 1)).West = IdentityStack(m, 1)
  2046.                     END SELECT
  2047.                 END IF
  2048.             NEXT
  2049.         NEXT
  2050.     NEXT
  2051.     a = IdentityStack(1 + IdentityStackSize, 1)
  2052.     FOR k = 1 TO UBOUND(SoftArrayRegister)
  2053.         IF (SoftArray(k).HeadNode) = x THEN
  2054.             a = Nodes(a).East
  2055.             EXIT FOR
  2056.         END IF
  2057.     NEXT
  2058.     IdentityStackSize = 0
  2059.     TheReturn = NewSoftArray("copy" + LTRIM$(RTRIM$(STR$(INT(TIMER * 10)))))
  2060.     b = LinkEast(TheReturn, a)
  2061.     CopyNodes = TheReturn
  2062.  
  2063. FUNCTION DeleteSoftArray (x AS INTEGER)
  2064.     DIM TheReturn AS LONG
  2065.     SoftArrayRegister(x) = -1
  2066.     TheReturn = DeleteNodesRecur(SoftArray(x).HeadNode)
  2067.     DeleteSoftArray = TheReturn
  2068.  
  2069. FUNCTION DeleteAllSoftArrays (x AS INTEGER)
  2070.     DIM TheReturn AS LONG
  2071.     DIM k AS INTEGER
  2072.     FOR k = x TO UBOUND(SoftArrayRegister)
  2073.         IF (SoftArrayRegister(k) <> -1) THEN
  2074.             TheReturn = DeleteSoftArray(k)
  2075.         END IF
  2076.     NEXT
  2077.     DeleteAllSoftArrays = TheReturn
  2078.  
  2079. FUNCTION SeverSoftArray (x AS INTEGER)
  2080.     ' Need to filter out case when node being severed is a head node. It makes no sense.
  2081.     DIM TheReturn AS LONG
  2082.     IF (Nodes(x).North <> -1) THEN
  2083.         Nodes(Nodes(x).North).South = -1
  2084.         Nodes(x).North = -1
  2085.     END IF
  2086.     IF (Nodes(x).West <> -1) THEN
  2087.         Nodes(Nodes(x).West).East = -1
  2088.     END IF
  2089.     TheReturn = NewSoftArray("sever" + LTRIM$(RTRIM$(STR$(INT(TIMER * 10)))))
  2090.     TheReturn = LinkEast(TheReturn, x)
  2091.     SeverSoftArray = TheReturn
  2092.  
  2093. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2094. ' Node creation
  2095. '
  2096.  
  2097. FUNCTION NextOpenIdentity (x AS LONG)
  2098.     DIM TheReturn AS LONG
  2099.     DIM k AS LONG
  2100.     TheReturn = -1
  2101.     FOR k = x TO UBOUND(IdentityRegister)
  2102.         IF (IdentityRegister(k) = -1) THEN
  2103.             TheReturn = k
  2104.             EXIT FOR
  2105.         END IF
  2106.     NEXT
  2107.     NextOpenIdentity = TheReturn
  2108.  
  2109. FUNCTION NewNode (x AS LONG, t AS STRING, r AS LONG)
  2110.     DIM i AS LONG
  2111.     i = NextOpenIdentity(x)
  2112.     IdentityRegister(i) = i
  2113.     Nodes(i).Identity = i
  2114.     Nodes(i).Species = t
  2115.     Nodes(i).Reference = r
  2116.     Nodes(i).North = -1
  2117.     Nodes(i).South = -1
  2118.     Nodes(i).East = -1
  2119.     Nodes(i).West = -1
  2120.     NewNode = i
  2121.  
  2122. FUNCTION CopyIntegerNode (x AS LONG)
  2123.     CopyIntegerNode = NewIntegerNode(IntegerData(Nodes(x).Reference))
  2124.  
  2125. FUNCTION ConvertToInteger (i AS LONG, x AS INTEGER)
  2126.     DIM TheReturn AS LONG
  2127.     Nodes(i).Species = "integer"
  2128.     Nodes(i).Reference = NewIntegerData(x)
  2129.     TheReturn = i
  2130.     ConvertToInteger = TheReturn
  2131.  
  2132. FUNCTION ConvertToText (i AS LONG, x AS STRING)
  2133.     DIM TheReturn AS LONG
  2134.     Nodes(i).Species = "text"
  2135.     Nodes(i).Reference = NewTextData(x)
  2136.     TheReturn = i
  2137.     ConvertToText = TheReturn
  2138.  
  2139. FUNCTION ConvertToDouble (i AS LONG, x AS DOUBLE)
  2140.     DIM TheReturn AS LONG
  2141.     Nodes(i).Species = "double"
  2142.     Nodes(i).Reference = NewDoubleData(x)
  2143.     TheReturn = i
  2144.     ConvertToDouble = TheReturn
  2145.  
  2146. FUNCTION NewIntegerNode (x AS INTEGER)
  2147.     NewIntegerNode = NewNode(1, "integer", NewIntegerData(x))
  2148.  
  2149. FUNCTION NewTextNode (x AS STRING)
  2150.     NewTextNode = NewNode(1, "text", NewTextData(x))
  2151.  
  2152. FUNCTION NewDoubleNode (x AS DOUBLE)
  2153.     NewDoubleNode = NewNode(1, "double", NewDoubleData(x))
  2154.  
  2155. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2156. ' Node editing
  2157. '
  2158.  
  2159. FUNCTION EditIntegerReference (x AS LONG, i AS INTEGER)
  2160.     DIM z AS LONG
  2161.     z = NewIntegerData(i)
  2162.     Nodes(x).Reference = z
  2163.     EditIntegerReference = z
  2164.  
  2165. FUNCTION EditTextReference (x AS LONG, t AS STRING)
  2166.     DIM z AS LONG
  2167.     z = NewTextData(t)
  2168.     Nodes(x).Reference = z
  2169.     EditTextReference = z
  2170.  
  2171. FUNCTION EditDoubleReference (x AS LONG, d AS DOUBLE)
  2172.     DIM z AS LONG
  2173.     z = NewDoubleData(d)
  2174.     Nodes(x).Reference = z
  2175.     EditDoubleReference = z
  2176.  
  2177. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2178. ' Data assimilation (prevents redundancy but can be disabled for more speed)
  2179. '
  2180.  
  2181. FUNCTION NewIntegerData (x AS INTEGER)
  2182.     DIM TheReturn AS LONG
  2183.     DIM k AS LONG
  2184.     TheReturn = -1
  2185.     FOR k = 1 TO UBOUND(IntegerData)
  2186.         IF (IntegerData(k) = x) THEN
  2187.             TheReturn = k
  2188.             EXIT FOR
  2189.         END IF
  2190.     NEXT
  2191.     IF (TheReturn = -1) THEN
  2192.         REDIM _PRESERVE IntegerData(UBOUND(IntegerData) + 1)
  2193.         IntegerData(UBOUND(IntegerData)) = x
  2194.         TheReturn = UBOUND(IntegerData)
  2195.     END IF
  2196.     NewIntegerData = TheReturn
  2197.  
  2198. FUNCTION NewTextData (x AS STRING)
  2199.     DIM TheReturn AS LONG
  2200.     DIM k AS LONG
  2201.     TheReturn = -1
  2202.     FOR k = 1 TO UBOUND(TextData)
  2203.         IF (TextData(k) = x) THEN
  2204.             TheReturn = k
  2205.             EXIT FOR
  2206.         END IF
  2207.     NEXT
  2208.     IF (TheReturn = -1) THEN
  2209.         REDIM _PRESERVE TextData(UBOUND(TextData) + 1)
  2210.         TextData(UBOUND(Textdata)) = x
  2211.         TheReturn = UBOUND(TextData)
  2212.     END IF
  2213.     NewTextData = TheReturn
  2214.  
  2215. FUNCTION NewDoubleData (x AS DOUBLE)
  2216.     DIM TheReturn AS LONG
  2217.     DIM k AS LONG
  2218.     TheReturn = -1
  2219.     FOR k = 1 TO UBOUND(DoubleData)
  2220.         IF (DoubleData(k) = x) THEN
  2221.             TheReturn = k
  2222.             EXIT FOR
  2223.         END IF
  2224.     NEXT
  2225.     IF (TheReturn = -1) THEN
  2226.         REDIM _PRESERVE DoubleData(UBOUND(DoubleData) + 1)
  2227.         DoubleData(UBOUND(DoubleData)) = x
  2228.         TheReturn = UBOUND(DoubleData)
  2229.     END IF
  2230.     NewDoubleData = TheReturn
  2231.  
  2232. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2233. ' End BM-component.
  2234. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2235.  
You're not done when it works, you're done when it's right.