Author Topic: A new take on arrays and data  (Read 3975 times)

0 Members and 1 Guest are viewing this topic.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #15 on: April 10, 2020, 01:11:25 am »
Alright, here is an important update in my opinion.

They say big projects should be designed to be tested early. As a worthwhile target that is more involved than just shoveling fake data around, I decided to write an expression evaluator that works by recursive tree traversal. I'm happy to report that it works.

In the screenshot below, you can see I set up the math problem 3 * 4 * cos (4 + 7) * 2 in a tree-like notation, namely:

Code: [Select]
*
  3
  4
  cos
    +
      4
      7
  2

Then, the code executes just one new function I called EvalStep to reduce that blob into an answer:

Code: [Select]
0.1062...
At no point do I swap numbers to a string representation and then switch back - this stays true to type.

Attachment at the bottom, newest and latest code here:

Code: QB64: [Select]
  1.  
  2. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  3. ' Hard arrays to store actual data:
  4. '
  5. REDIM SHARED IntegerData(0) AS INTEGER
  6. REDIM SHARED StringData(0) AS STRING
  7. REDIM SHARED DoubleData(0) AS DOUBLE
  8.  
  9. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  10. ' Elements:
  11. '
  12.  
  13. ' Elemental structure
  14. TYPE Element
  15.     Identity AS LONG '   Address
  16.     Species AS STRING '  Data type
  17.     Reference AS LONG '  Pointer to hard array index
  18.     North AS LONG '
  19.     South AS LONG '
  20.     East AS LONG '
  21.     West AS LONG '       (Orientation)
  22.  
  23. DIM MaxElements AS INTEGER
  24. MaxElements = 9999
  25.  
  26. ' Element visibility toggle
  27. DIM SHARED IdentityRegister(MaxElements) AS LONG
  28. FOR k = 1 TO UBOUND(IdentityRegister)
  29.     IdentityRegister(k) = 0
  30.  
  31. ' Element storage
  32. DIM SHARED Elements(MaxElements) AS Element
  33.  
  34. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  35. ' Soft Arrays:
  36. '
  37.  
  38. ' Soft array structure
  39. TYPE SoftArrayMeta
  40.     Label AS STRING
  41.     FirstElement AS LONG
  42.  
  43. DIM MaxSoftArrays AS INTEGER
  44. MaxSoftArrays = 99
  45.  
  46. ' Soft array visibility toggle
  47. DIM SHARED SoftArrayRegister(MaxSoftArrays) AS INTEGER
  48. FOR k = 1 TO UBOUND(SoftArrayRegister)
  49.     SoftArrayRegister(k) = 0
  50.  
  51. ' Soft array storage
  52. DIM SHARED SoftArray(MaxSoftArrays) AS SoftArrayMeta
  53.  
  54. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  55. ' Setup
  56. '
  57.  
  58.  
  59. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  60. ' Main
  61. '
  62.  
  63. CALL DemoArray3D
  64. PRINT "Press any key..."
  65. CALL DemoTree
  66. PRINT "Press any key..."
  67. CALL DemoTreeEdit
  68. PRINT "Press any key..."
  69. CALL DemoArithmetic
  70.  
  71.  
  72. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  73. ' Example cases:
  74. '
  75.  
  76. SUB DemoArithmetic
  77.     DIM a AS LONG
  78.     DIM b AS LONG
  79.  
  80.     a = NewSoftArray(0, "Arithmetic Test")
  81.     a = LinkEast(a, NewStringElement("*"))
  82.     b = LinkEast(a, NewIntegerElement(3))
  83.     b = LinkSouth(b, NewIntegerElement(4))
  84.     a = LinkSouth(b, NewStringElement("cos"))
  85.     b = LinkEast(a, NewStringElement("+"))
  86.     b = LinkEast(b, NewIntegerElement(4))
  87.     b = LinkSouth(b, NewIntegerElement(7))
  88.     'b = LinkSouth(b, NewStringElement("seventeen"))
  89.     b = LinkSouth(a, NewIntegerElement(2))
  90.  
  91.     ' Display and query tests
  92.     CALL PrintSoftArray(ArrayId("Arithmetic Test"))
  93.     PRINT
  94.     PRINT "..."
  95.     CALL EvalStep(FirstEmbedded(SoftArray(ArrayId("Arithmetic Test")).FirstElement))
  96.     CALL PrintSoftArray(ArrayId("Arithmetic Test"))
  97.     PRINT
  98.     PRINT "..."
  99.     CALL EvalStep(FirstEmbedded(SoftArray(ArrayId("Arithmetic Test")).FirstElement))
  100.     CALL PrintSoftArray(ArrayId("Arithmetic Test"))
  101.     PRINT
  102.     PRINT "..."
  103.     CALL EvalStep(FirstEmbedded(SoftArray(ArrayId("Arithmetic Test")).FirstElement))
  104.     CALL PrintSoftArray(ArrayId("Arithmetic Test"))
  105.  
  106. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  107.  
  108. SUB DemoTreeEdit
  109.     DIM a AS LONG
  110.     DIM b AS LONG
  111.     DIM c AS LONG
  112.  
  113.     a = NewSoftArray(0, "Tree Edit Test")
  114.     a = LinkEast(a, NewStringElement("QB64 Buddy"))
  115.     a = LinkEast(a, NewStringElement("Handle"))
  116.     b = LinkEast(a, NewStringElement("flukiluke"))
  117.     a = LinkSouth(a, NewStringElement("Name"))
  118.     b = LinkEast(a, NewStringElement("Luke C."))
  119.     a = LinkSouth(a, NewStringElement("Country"))
  120.     b = LinkEast(a, NewStringElement("Australia"))
  121.     c = LinkEast(b, NewStringElement("Locality"))
  122.     b = LinkEast(c, NewStringElement("Down Under"))
  123.     a = LinkSouth(a, NewStringElement("Birthyear"))
  124.     b = LinkEast(a, NewIntegerElement(1523))
  125.     c = LinkSouth(b, NewStringElement("May?"))
  126.  
  127.     ' Display and query tests
  128.     CALL PrintSoftArray(ArrayId("Tree Edit Test"))
  129.     PRINT
  130.  
  131.     PRINT "Inserting `Get it?' into list..."
  132.     a = InsertEast(SeekString("Down Under", FromLabel("Tree Edit Test"), 1), NewStringElement("Get it?"))
  133.     PRINT "Adding new entry to bottom of list..."
  134.     a = InsertSouth(SeekString("QB64 Buddy", FromLabel("Tree Edit Test"), 1), NewStringElement("QB64 Enemy"))
  135.     PRINT "Editing Birthyear..."
  136.     a = EditIntegerReference(StepUsing(SeekString("Birthyear", FromLabel("Tree Edit Test"), 1), "e"), 1855)
  137.     PRINT "Deleting a few entries under Country..."
  138.     a = LinkEast(SeekString("Country", FromLabel("Tree Edit Test"), 1), SeekString("Down Under", FromLabel("Tree Edit Test"), 1))
  139.     PRINT "Unlinking Name (and child elements)..."
  140.     a = Unlink(SeekString("Name", FromLabel("Tree Edit Test"), 1))
  141.  
  142.     PRINT
  143.     CALL PrintSoftArray(ArrayId("Tree Edit Test"))
  144.  
  145. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  146.  
  147. SUB DemoTree
  148.     DIM a AS LONG
  149.     DIM b AS LONG
  150.     DIM c AS LONG
  151.     DIM d AS LONG
  152.  
  153.     a = NewSoftArray(0, "Tree of Friends")
  154.     a = LinkEast(a, NewStringElement("QB64 Buddy")): d = a
  155.     a = LinkEast(a, NewStringElement("Handle"))
  156.     b = LinkEast(a, NewStringElement("SMcNeill"))
  157.     a = LinkSouth(a, NewStringElement("Name"))
  158.     b = LinkEast(a, NewStringElement("Steve SMcNeill"))
  159.     a = LinkSouth(a, NewStringElement("Country"))
  160.     b = LinkEast(a, NewStringElement("USA"))
  161.     c = LinkEast(b, NewStringElement("Locality"))
  162.     b = LinkEast(c, NewStringElement("Virginia"))
  163.     a = LinkSouth(a, NewStringElement("Birthyear"))
  164.     b = LinkEast(a, NewIntegerElement(1973))
  165.     c = LinkSouth(b, NewStringElement("May?"))
  166.     a = LinkSouth(d, NewStringElement("QB64 Buddy")): d = a
  167.     a = LinkEast(a, NewStringElement("Handle"))
  168.     b = LinkEast(a, NewStringElement("FellippeHeitor"))
  169.     a = LinkSouth(a, NewStringElement("Name"))
  170.     b = LinkEast(a, NewStringElement("Fellippe Heitor"))
  171.     a = LinkSouth(a, NewStringElement("Country"))
  172.     b = LinkEast(a, NewStringElement("Brazil"))
  173.     c = LinkEast(b, NewStringElement("Locality"))
  174.     b = LinkEast(c, NewStringElement("My <3"))
  175.     c = LinkEast(b, NewStringElement("JK, it's ___."))
  176.     a = LinkSouth(a, NewStringElement("Birthyear"))
  177.     b = LinkEast(a, NewIntegerElement(1983))
  178.     c = LinkSouth(b, NewStringElement("Sep?"))
  179.     b = LinkSouth(c, NewStringElement("... or was it May?"))
  180.     a = LinkSouth(d, NewStringElement("QB64 Buddy")): d = a
  181.     a = LinkEast(a, NewStringElement("Handle"))
  182.     b = LinkEast(a, NewStringElement("DanTurtle"))
  183.  
  184.     ' Display array
  185.     CALL PrintSoftArray(ArrayId("Tree of Friends"))
  186.     PRINT
  187.  
  188.     ' Query tests
  189.     PRINT "Height:"; SoftArrayHeight(ArrayId("Tree of Friends"))
  190.     PRINT "Steve's locality: "; Literal$(StepFromLabel("Tree of Friends", "eesseee"))
  191.     PRINT "Fellippe's locality: "; Literal$(StepFromLabel("Tree of Friends", "esesseee"))
  192.     PRINT "Fellippe's birth month: "; Literal$(StepUsing(JumpFrom(StepFromLabel("Tree of Friends", "ese"), "s", 3), "es"))
  193.     PRINT "Width of Fellippe's Country branch:"; Measure(SeekString("Country", FromLabel("Tree of Friends"), 2), "e")
  194.     PRINT "Height under Fellippe's Birthyear branch:"; Measure(Elements(SeekString("Birthyear", FromLabel("Tree of Friends"), 2)).East, "s")
  195.  
  196. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  197.  
  198. SUB DemoArray3D
  199.     DIM TestArray3D(4, 2, 3) AS STRING
  200.     TestArray3D(1, 1, 1) = "one.one.one"
  201.     TestArray3D(1, 1, 2) = "one.one.two"
  202.     TestArray3D(1, 1, 3) = "one.one.three"
  203.     TestArray3D(1, 2, 1) = "one.two.one"
  204.     TestArray3D(1, 2, 2) = "one.two.two"
  205.     TestArray3D(1, 2, 3) = "one.two.three"
  206.     TestArray3D(2, 1, 1) = "two.one.one"
  207.     TestArray3D(2, 1, 2) = "two.one.two"
  208.     TestArray3D(2, 1, 3) = "two.one.three"
  209.     TestArray3D(2, 2, 1) = "two.two.one"
  210.     TestArray3D(2, 2, 2) = "two.two.two"
  211.     TestArray3D(2, 2, 3) = "two.two.three"
  212.     TestArray3D(3, 1, 1) = "three.one.one"
  213.     TestArray3D(3, 1, 2) = "three.one.two"
  214.     TestArray3D(3, 1, 3) = "three.one.three"
  215.     TestArray3D(3, 2, 1) = "three.two.one"
  216.     TestArray3D(3, 2, 2) = "three.two.two"
  217.     TestArray3D(3, 2, 3) = "three.two.three"
  218.     TestArray3D(4, 1, 1) = "four.one.one"
  219.     TestArray3D(4, 1, 2) = "four.one.two"
  220.     TestArray3D(4, 1, 3) = "four.one.three"
  221.     TestArray3D(4, 2, 1) = "four.two.one"
  222.     TestArray3D(4, 2, 2) = "four.two.two"
  223.     TestArray3D(4, 2, 3) = "four.two.three"
  224.     DIM i AS INTEGER
  225.     DIM j AS INTEGER
  226.     DIM k AS INTEGER
  227.     DIM a AS LONG
  228.     DIM b AS LONG
  229.     a = NewSoftArray(0, "Three-Dimensional Array")
  230.     FOR i = 1 TO UBOUND(TestArray3D, 1)
  231.         FOR j = 1 TO UBOUND(TestArray3D, 2)
  232.             FOR k = 1 TO UBOUND(TestArray3D, 3)
  233.                 IF ((i = 1) AND (j = 1) AND (k = 1)) THEN
  234.                     a = LinkEast(a, NewStringElement(TestArray3D(i, j, k)))
  235.                     b = a
  236.                 ELSE
  237.                     IF (k = 1) THEN
  238.                         a = LinkSouth(a, NewStringElement(TestArray3D(i, j, k)))
  239.                         b = a
  240.                     ELSE
  241.                         b = LinkEast(b, NewStringElement(TestArray3D(i, j, k)))
  242.                     END IF
  243.                 END IF
  244.             NEXT
  245.         NEXT
  246.     NEXT
  247.  
  248.     ' Display array
  249.     CALL PrintSoftArray(ArrayId("Three-Dimensional Array"))
  250.     PRINT
  251.  
  252.     ' Query tests
  253.     PRINT "Height:"; SoftArrayHeight(ArrayId("Three-Dimensional Array"))
  254.     PRINT "Width:"; SoftArrayWidth(ArrayId("Three-Dimensional Array"))
  255.  
  256. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  257. ' Processing
  258. '
  259.  
  260. SUB EvalStep (x AS LONG)
  261.     DIM SouthernId AS LONG
  262.     DIM NorthernId AS LONG
  263.     DIM FunctionId AS LONG
  264.     DIM i AS LONG
  265.     DIM n AS LONG
  266.     DIM s AS LONG
  267.     DIM RefSpecies AS STRING
  268.     DIM ReturnSpecies AS STRING
  269.     DIM ReturnInteger AS INTEGER
  270.     DIM ReturnString AS STRING
  271.     DIM ReturnDouble AS DOUBLE
  272.     RefSpecies = "integer"
  273.     ReturnSpecies = ""
  274.     ReturnInteger = 0
  275.     ReturnString = ""
  276.     ReturnDouble = 0
  277.  
  278.     IF (x <> -1) THEN
  279.         SouthernId = x
  280.         i = x
  281.         DO
  282.             IF (Elements(i).Species = "string") THEN RefSpecies = "string"
  283.             IF (Elements(i).Species = "double") THEN RefSpecies = "double"
  284.             n = Elements(i).North
  285.             IF (n <> -1) THEN
  286.                 i = n
  287.             ELSE
  288.                 NorthernId = i
  289.                 EXIT DO
  290.             END IF
  291.         LOOP
  292.         FunctionId = Elements(NorthernId).West
  293.     END IF
  294.  
  295.     SELECT CASE Literal$(FunctionId)
  296.         CASE "*"
  297.             ReturnSpecies = RefSpecies
  298.             ReturnInteger = 1
  299.             ReturnDouble = 1
  300.         CASE "+"
  301.             ReturnSpecies = RefSpecies
  302.             ReturnInteger = 0
  303.             ReturnDouble = 0
  304.     END SELECT
  305.  
  306.     i = NorthernId
  307.     DO
  308.         SELECT CASE Literal$(FunctionId)
  309.             CASE "*"
  310.                 SELECT CASE ReturnSpecies
  311.                     CASE "integer"
  312.                         SELECT CASE Elements(i).Species
  313.                             CASE "integer"
  314.                                 ReturnInteger = ReturnInteger * IntegerData(Elements(i).Reference)
  315.                             CASE "double"
  316.                                 ReturnInteger = ReturnInteger * DoubleData(Elements(i).Reference)
  317.                         END SELECT
  318.                     CASE "string"
  319.                         ReturnString = ReturnString + Literal$(i)
  320.                     CASE "double"
  321.                         SELECT CASE Elements(i).Species
  322.                             CASE "integer"
  323.                                 ReturnDouble = ReturnDouble * IntegerData(Elements(i).Reference)
  324.                             CASE "double"
  325.                                 ReturnDouble = ReturnDouble * DoubleData(Elements(i).Reference)
  326.                         END SELECT
  327.                 END SELECT
  328.  
  329.             CASE "+"
  330.                 SELECT CASE ReturnSpecies
  331.                     CASE "integer"
  332.                         SELECT CASE Elements(i).Species
  333.                             CASE "integer"
  334.                                 ReturnInteger = ReturnInteger + IntegerData(Elements(i).Reference)
  335.                             CASE "double"
  336.                                 ReturnInteger = ReturnInteger + DoubleData(Elements(i).Reference)
  337.                         END SELECT
  338.                     CASE "string"
  339.                         ReturnString = ReturnString + Literal$(i)
  340.                     CASE "double"
  341.                         SELECT CASE Elements(i).Species
  342.                             CASE "integer"
  343.                                 ReturnDouble = ReturnDouble + IntegerData(Elements(i).Reference)
  344.                             CASE "double"
  345.                                 ReturnDouble = ReturnDouble + DoubleData(Elements(i).Reference)
  346.                         END SELECT
  347.                 END SELECT
  348.             CASE "cos"
  349.  
  350.                 SELECT CASE Elements(i).Species
  351.                     CASE "integer"
  352.                         ReturnSpecies = "double"
  353.                         ReturnDouble = COS(IntegerData(Elements(i).Reference))
  354.                     CASE "string"
  355.                         ReturnSpecies = "string"
  356.                         ReturnString = "cos(" + Literal$(i) + ")"
  357.                     CASE "double"
  358.                         ReturnSpecies = "double"
  359.                         ReturnDouble = COS(DoubleData(Elements(i).Reference))
  360.                 END SELECT
  361.         END SELECT
  362.  
  363.         IF (i = SouthernId) THEN
  364.             i = Unlink(i)
  365.             EXIT DO
  366.         ELSE
  367.             s = Elements(i).South
  368.             i = Unlink(i)
  369.             i = s
  370.         END IF
  371.     LOOP
  372.  
  373.     Elements(FunctionId).Species = ReturnSpecies
  374.     SELECT CASE ReturnSpecies
  375.         CASE "integer"
  376.             Elements(FunctionId).Reference = NewIntegerData(ReturnInteger)
  377.         CASE "string"
  378.             Elements(FunctionId).Reference = NewStringData(ReturnString)
  379.         CASE "double"
  380.             Elements(FunctionId).Reference = NewDoubleData(ReturnDouble)
  381.     END SELECT
  382.  
  383. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  384. ' Seek and recall
  385. '
  386.  
  387. FUNCTION ArrayId (x AS STRING)
  388.     DIM TheReturn AS LONG
  389.     DIM k AS LONG
  390.     TheReturn = -1
  391.     FOR k = 1 TO UBOUND(SoftArray)
  392.         IF (SoftArray(k).Label = x) THEN
  393.             TheReturn = k
  394.             EXIT FOR
  395.         END IF
  396.     NEXT
  397.     ArrayId = TheReturn
  398.  
  399. FUNCTION SeekString (t AS STRING, x AS LONG, r AS INTEGER)
  400.     DIM TheReturn AS LONG
  401.     DIM s AS LONG
  402.     DIM e AS LONG
  403.     TheReturn = -1
  404.     s = Elements(x).South
  405.     e = Elements(x).East
  406.     IF (StringData(Elements(x).Reference) = t) THEN
  407.         TheReturn = x
  408.         r = r - 1
  409.     ELSE
  410.         IF (e <> -1) AND (r > 0) THEN
  411.             TheReturn = SeekString(t, e, r)
  412.         END IF
  413.         IF (s <> -1) AND (r > 0) THEN
  414.             TheReturn = SeekString(t, s, r)
  415.         END IF
  416.     END IF
  417.     SeekString = TheReturn
  418.  
  419. FUNCTION FirstEmbedded (x AS LONG)
  420.     DIM TheReturn AS LONG
  421.     TheReturn = MostEmbeddedRecur(x, -1)
  422.     FirstEmbedded = TheReturn
  423.  
  424. FUNCTION MostEmbeddedRecur (x AS LONG, y AS LONG)
  425.     DIM TheReturn AS LONG
  426.     DIM s AS LONG
  427.     DIM e AS LONG
  428.     s = Elements(x).South
  429.     e = Elements(x).East
  430.     IF (e <> -1) THEN
  431.         TheReturn = MostEmbeddedRecur(e, y)
  432.     END IF
  433.     IF (s <> -1) THEN
  434.         TheReturn = MostEmbeddedRecur(s, y)
  435.     END IF
  436.     IF (e = -1) AND (s = -1) AND (y = -1) THEN
  437.         y = x
  438.     END IF
  439.     MostEmbeddedRecur = y
  440.  
  441. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  442. ' Navigation
  443. '
  444.  
  445. FUNCTION FromLabel (x AS STRING)
  446.     DIM TheReturn AS LONG
  447.     TheReturn = SoftArray(ArrayId(x)).FirstElement
  448.     FromLabel = TheReturn
  449.  
  450. FUNCTION StepFromLabel (x AS STRING, t AS STRING)
  451.     DIM TheReturn AS LONG
  452.     TheReturn = StepUsing(FromLabel(x), t)
  453.     StepFromLabel = TheReturn
  454.  
  455. FUNCTION JumpFrom (x AS LONG, t AS STRING, r AS INTEGER)
  456.     DIM TheReturn AS LONG
  457.     TheReturn = x
  458.     IF (r > 0) THEN
  459.         SELECT CASE t
  460.             CASE "n"
  461.                 TheReturn = JumpFrom(Elements(x).North, "n", r - 1)
  462.             CASE "s"
  463.                 TheReturn = JumpFrom(Elements(x).South, "s", r - 1)
  464.             CASE "e"
  465.                 TheReturn = JumpFrom(Elements(x).East, "e", r - 1)
  466.             CASE "w"
  467.                 TheReturn = JumpFrom(Elements(x).West, "w", r - 1)
  468.         END SELECT
  469.     END IF
  470.     JumpFrom = TheReturn
  471.  
  472. FUNCTION StepUsing (x AS LONG, t AS STRING)
  473.     DIM TheReturn AS LONG
  474.     DIM k AS INTEGER
  475.     DIM i AS LONG
  476.     DIM j AS LONG
  477.     i = x
  478.     FOR k = 1 TO LEN(t)
  479.         SELECT CASE MID$(t, k, 1)
  480.             CASE "n"
  481.                 j = Elements(i).North
  482.                 IF (j <> -1) THEN i = j
  483.             CASE "s"
  484.                 j = Elements(i).South
  485.                 IF (j <> -1) THEN i = j
  486.             CASE "e"
  487.                 j = Elements(i).East
  488.                 IF (j <> -1) THEN i = j
  489.             CASE "w"
  490.                 j = Elements(i).West
  491.                 IF (j <> -1) THEN i = j
  492.         END SELECT
  493.     NEXT
  494.     TheReturn = i
  495.     StepUsing = TheReturn
  496.  
  497. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  498. ' Internal metrics
  499. '
  500.  
  501. FUNCTION SoftArrayHeight (x AS INTEGER)
  502.     DIM TheReturn AS INTEGER
  503.     TheReturn = Measure(Elements(SoftArray(x).FirstElement).East, "s")
  504.     SoftArrayHeight = TheReturn
  505.  
  506. FUNCTION SoftArrayWidth (x AS INTEGER)
  507.     DIM TheReturn AS INTEGER
  508.     TheReturn = Measure(Elements(SoftArray(x).FirstElement).East, "e")
  509.     SoftArrayWidth = TheReturn
  510.  
  511. FUNCTION Measure (x AS LONG, t AS STRING)
  512.     DIM TheReturn AS INTEGER
  513.     TheReturn = CountSteps(x, -1, t)
  514.     Measure = TheReturn
  515.  
  516. FUNCTION CountSteps (x AS LONG, y AS LONG, t AS STRING)
  517.     DIM TheReturn AS INTEGER
  518.     DIM k AS LONG
  519.     TheReturn = 0
  520.     SELECT CASE t
  521.         CASE "n"
  522.             k = Elements(x).North
  523.         CASE "s"
  524.             k = Elements(x).South
  525.         CASE "e"
  526.             k = Elements(x).East
  527.         CASE "w"
  528.             k = Elements(x).West
  529.     END SELECT
  530.     IF (k = y) THEN
  531.         TheReturn = TheReturn + 1
  532.     ELSE
  533.         IF (k <> -1) THEN
  534.             TheReturn = TheReturn + 1 + CountSteps(k, y, t)
  535.         END IF
  536.     END IF
  537.     CountSteps = TheReturn
  538.  
  539. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  540. ' Printing and reporting
  541. '
  542.  
  543. SUB PrintSoftArray (x AS LONG)
  544.     DIM t AS STRING
  545.     IF (x <> -1) THEN
  546.         t = ListElementsRecur$(0, SoftArray(x).FirstElement)
  547.     END IF
  548.     t = LEFT$(t, LEN(t) - 1)
  549.     PRINT t
  550.  
  551. FUNCTION ListElementsRecur$ (i AS INTEGER, x AS LONG)
  552.     DIM TheReturn AS STRING
  553.     DIM s AS LONG
  554.     DIM e AS LONG
  555.     s = Elements(x).South
  556.     e = Elements(x).East
  557.     TheReturn = TheReturn + SPACE$(i) + Literal$(x) + CHR$(10)
  558.     IF (e <> -1) THEN
  559.         TheReturn = TheReturn + ListElementsRecur$(i + 2, e)
  560.     END IF
  561.     IF (s <> -1) THEN
  562.         TheReturn = TheReturn + ListElementsRecur$(i, s)
  563.     END IF
  564.     ListElementsRecur$ = TheReturn
  565.  
  566. FUNCTION Literal$ (x AS LONG)
  567.     DIM TheReturn AS STRING
  568.     TheReturn = ""
  569.     SELECT CASE Elements(x).Species
  570.         CASE "integer"
  571.             TheReturn = LTRIM$(RTRIM$(STR$(IntegerData(Elements(x).Reference))))
  572.         CASE "string"
  573.             TheReturn = StringData(Elements(x).Reference)
  574.         CASE "double"
  575.             TheReturn = LTRIM$(RTRIM$(STR$(DoubleData(Elements(x).Reference))))
  576.     END SELECT
  577.     Literal$ = TheReturn
  578.  
  579. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  580. ' Soft array construction
  581. '
  582.  
  583. FUNCTION NextOpenSoftArray (x AS LONG)
  584.     DIM TheReturn AS LONG
  585.     DIM k AS LONG
  586.     TheReturn = -1
  587.     FOR k = x TO UBOUND(SoftArrayRegister)
  588.         IF (SoftArrayRegister(k) = 0) THEN
  589.             TheReturn = k
  590.             EXIT FOR
  591.         END IF
  592.     NEXT
  593.     NextOpenSoftArray = TheReturn
  594.  
  595. FUNCTION NewSoftArray (i AS INTEGER, t AS STRING)
  596.     DIM k AS LONG
  597.     k = NewStringElement(t)
  598.     IF (i < 1) THEN
  599.         i = NextOpenSoftArray(1)
  600.         SoftArrayRegister(i) = i
  601.     END IF
  602.     SoftArray(i).Label = StringData(Elements(k).Reference)
  603.     SoftArray(i).FirstElement = k
  604.     NewSoftArray = k
  605.  
  606. FUNCTION LinkSouth (n AS LONG, s AS LONG)
  607.     DIM TheReturn AS LONG
  608.     Elements(s).North = n
  609.     Elements(n).South = s
  610.     TheReturn = s
  611.     LinkSouth = TheReturn
  612.  
  613. FUNCTION LinkEast (w AS LONG, e AS LONG)
  614.     DIM TheReturn AS LONG
  615.     Elements(w).East = e
  616.     Elements(e).West = w
  617.     TheReturn = e
  618.     LinkEast = TheReturn
  619.  
  620. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  621. ' Soft array editing
  622. '
  623. FUNCTION InsertSouth (n AS LONG, x AS LONG)
  624.     DIM s AS LONG
  625.     s = Elements(n).South
  626.     Elements(n).South = x
  627.     Elements(x).North = n
  628.     Elements(x).South = s
  629.     IF (s <> -1) THEN
  630.         Elements(s).North = x
  631.     END IF
  632.     InsertSouth = x
  633.  
  634. FUNCTION InsertEast (w AS LONG, x AS LONG)
  635.     DIM e AS LONG
  636.     e = Elements(w).East
  637.     Elements(w).East = x
  638.     Elements(x).West = w
  639.     Elements(x).East = e
  640.     IF (e <> -1) THEN
  641.         Elements(e).West = x
  642.     END IF
  643.     InsertEast = x
  644.  
  645. FUNCTION Unlink (x AS LONG)
  646.     DIM n AS LONG
  647.     DIM s AS LONG
  648.     DIM e AS LONG
  649.     DIM w AS LONG
  650.     n = Elements(x).North
  651.     s = Elements(x).South
  652.     e = Elements(x).East
  653.     w = Elements(x).West
  654.     IF (n <> -1) THEN Elements(n).South = s
  655.     IF (s <> -1) THEN Elements(s).North = n
  656.     IF (e <> -1) THEN Elements(e).West = w
  657.     IF (w <> -1) THEN Elements(w).East = e
  658.     IdentityRegister(x) = 0
  659.     Unlink = x
  660.  
  661. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  662. ' Element creation
  663. '
  664.  
  665. FUNCTION NextOpenIdentity (x AS LONG)
  666.     DIM TheReturn AS LONG
  667.     DIM k AS LONG
  668.     TheReturn = -1
  669.     FOR k = x TO UBOUND(IdentityRegister)
  670.         IF (IdentityRegister(k) = 0) THEN
  671.             TheReturn = k
  672.             EXIT FOR
  673.         END IF
  674.     NEXT
  675.     NextOpenIdentity = TheReturn
  676.  
  677. FUNCTION NewElement (x AS LONG, t AS STRING, r AS LONG)
  678.     DIM i AS LONG
  679.     i = NextOpenIdentity(x)
  680.     IdentityRegister(i) = i
  681.     Elements(i).Identity = i
  682.     Elements(i).Species = t
  683.     Elements(i).Reference = r
  684.     Elements(i).North = -1
  685.     Elements(i).South = -1
  686.     Elements(i).East = -1
  687.     Elements(i).West = -1
  688.     NewElement = i
  689.  
  690. FUNCTION NewIntegerElement (x AS INTEGER)
  691.     NewIntegerElement = NewElement(1, "integer", NewIntegerData(x))
  692.  
  693. FUNCTION NewStringElement (x AS STRING)
  694.     NewStringElement = NewElement(1, "string", NewStringData(x))
  695.  
  696. FUNCTION NewDoubleElement (x AS DOUBLE)
  697.     NewDoubleElement = NewElement(1, "double", NewDoubleData(x))
  698.  
  699. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  700. ' Element editing
  701. '
  702.  
  703. FUNCTION EditIntegerReference (i AS LONG, x AS INTEGER)
  704.     DIM z AS LONG
  705.     z = NewIntegerData(x)
  706.     Elements(i).Reference = z
  707.     EditIntegerReference = z
  708.  
  709. FUNCTION EditStringReference (i AS LONG, x AS STRING)
  710.     DIM z AS LONG
  711.     z = NewStringData(x)
  712.     Elements(i).Reference = z
  713.     EditStringReference = z
  714.  
  715. FUNCTION EditDoubleReference (i AS LONG, x AS DOUBLE)
  716.     DIM z AS LONG
  717.     z = NewDoubleData(x)
  718.     Elements(i).Reference = z
  719.     EditDoubleReference = z
  720.  
  721. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  722. ' Data assimilation
  723. '
  724.  
  725. FUNCTION NewIntegerData (x AS INTEGER)
  726.     DIM TheReturn AS LONG
  727.     DIM k AS LONG
  728.     TheReturn = -1
  729.     FOR k = 1 TO UBOUND(IntegerData)
  730.         IF (IntegerData(k) = x) THEN
  731.             TheReturn = k
  732.             EXIT FOR
  733.         END IF
  734.     NEXT
  735.     IF (TheReturn = -1) THEN
  736.         REDIM _PRESERVE IntegerData(UBOUND(IntegerData) + 1)
  737.         IntegerData(UBOUND(IntegerData)) = x
  738.         TheReturn = UBOUND(IntegerData)
  739.     END IF
  740.     NewIntegerData = TheReturn
  741.  
  742. FUNCTION NewStringData (x AS STRING)
  743.     DIM TheReturn AS LONG
  744.     DIM k AS LONG
  745.     TheReturn = -1
  746.     FOR k = 1 TO UBOUND(StringData)
  747.         IF (StringData(k) = x) THEN
  748.             TheReturn = k
  749.             EXIT FOR
  750.         END IF
  751.     NEXT
  752.     IF (TheReturn = -1) THEN
  753.         REDIM _PRESERVE StringData(UBOUND(StringData) + 1)
  754.         StringData(UBOUND(Stringdata)) = x
  755.         TheReturn = UBOUND(StringData)
  756.     END IF
  757.     NewStringData = TheReturn
  758.  
  759. FUNCTION NewDoubleData (x AS DOUBLE)
  760.     DIM TheReturn AS LONG
  761.     DIM k AS LONG
  762.     TheReturn = -1
  763.     FOR k = 1 TO UBOUND(DoubleData)
  764.         IF (DoubleData(k) = x) THEN
  765.             TheReturn = k
  766.             EXIT FOR
  767.         END IF
  768.     NEXT
  769.     IF (TheReturn = -1) THEN
  770.         REDIM _PRESERVE DoubleData(UBOUND(DoubleData) + 1)
  771.         DoubleData(UBOUND(DoubleData)) = x
  772.         TheReturn = UBOUND(DoubleData)
  773.     END IF
  774.     NewDoubleData = TheReturn
  775.  
  776. 'SUB ResetStack
  777. '    REDIM _PRESERVE IdentityStack(0)
  778. 'END SUB
  779.  
  780. 'FUNCTION NewStackId (x AS LONG)
  781. '    REDIM _PRESERVE IdentityStack(UBOUND(IdentityStack) + 1)
  782. '    IdentityStack(UBOUND(IdentityStack)) = x
  783. '    NewStackId = x
  784. 'END SUB
  785.  
sss.png
* sss.png (Filesize: 4.88 KB, Dimensions: 640x672, Views: 317)
« Last Edit: April 10, 2020, 01:23:07 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #16 on: April 12, 2020, 08:59:14 am »
I'm calling this the Anonymous Function update.

How to explain this... okay... so QB64 doesn't natively support lambda expressions, anonymous functions, combinators - none of the high-level egghead stuff. I began thinking about why most of us haven't heard of these things, and I conclude it's because QB64 is a high-level language that uses low-level semantics. If QB64 had a keyword for it, you would all be experts on it. But when there isn't, it's great pain for everyone, am I wrong? Anyway, if we want QB64 to behave more abstractly, we have to roll our own and not wait for version 1.9 or whatever. This sentiment transitions right into a nice quote summarizing why there is a drive for math evaluators, sub-languages, etc. - basically anything in our Interpreters section in the Library:

Quote
Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp. - Greenspun's tenth rule of programming

Fast Review of Functions

Consider the QB64 function of three arguments that returns a number:
Code: QB64: [Select]
  1. FUNCTION DoMath (x, y, z)
  2.     DoMath = 3 * x + 4 * y - 2 * z

To call the function, you need to type the name and the correct number of arguments, as in
Code: QB64: [Select]
  1. PRINT DoMath(4, 5, 6)

... which gives a result of 20.

Anonymous Function

Functional languages allow the coder to (i) define, (ii) send arguments, and (iii) use a function all in one step, without ever naming the function. This is why it's called anonymous. Wouldn't be interesting then, if QB64 had the same thing, where we might type something like

Code: QB64: [Select]
  1. PRINT {3*x + 4*y - 5*z} (3,4,5)

... to produce the same 20. Now, this still may seem trivial, or equivalent to the old DEF FN if we want to use this idea all alone, surrounded by the pithy matrix of QB64-ness. Alas, this stuff has much more power when your surrounding paradigm leans functional, meaning functions and code are passed around as data. I know that sounds weird, and I'm afraid I won't try to justify it in this paragraph.

So what's new with this code?

The Soft Arrays codebase now evaluates anonymous functions (triggered by the lambda keyword). To explain, consider the QB64 code

Code: QB64: [Select]
  1. PRINT DoMath(4, 6)
  2.  
  3. FUNCTION DoMath (x, y)
  4.     DoMath = COS(3 * x * 5 * y)

... which prints something like -.284. Of course, in a tighter pseudo-anonymous notation, we may write

Code: QB64: [Select]
  1. PRINT {COS(3*x*5*y)} (4,6)

Now, forgive how expanded the syntax is for now (this will tighten up later)... but the EXACT same calculation, as expressed via a linked list, looks like:

Code: QB64: [Select]
  1.     a = NewSoftArray(0, "Lambda Test")
  2.     a = LinkEast(a, NewStringElement("lambda"))
  3.     b = LinkEast(a, NewIntegerElement(4))
  4.     b = LinkSouth(b, NewIntegerElement(6))
  5.     a = LinkSouth(a, NewStringElement("cos"))
  6.     b = LinkEast(a, NewStringElement("*"))
  7.     b = LinkEast(b, NewIntegerElement(3))
  8.     b = LinkSouth(b, NewStringElement("[1]"))
  9.     b = LinkSouth(b, NewIntegerElement(5))
  10.     b = LinkSouth(b, NewStringElement("[2]"))

... which, when I run my new magic Evaluate function, gives the correct answer as shown in the screenshot.

Full code below:

Code: QB64: [Select]
  1.  
  2. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  3. ' Hard arrays to store actual data:
  4. '
  5. REDIM SHARED IntegerData(0) AS INTEGER
  6. REDIM SHARED StringData(0) AS STRING
  7. REDIM SHARED DoubleData(0) AS DOUBLE
  8.  
  9. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  10. ' Elements:
  11. '
  12.  
  13. ' Elemental structure
  14. TYPE Element
  15.     Identity AS LONG '   Address
  16.     Species AS STRING '  Data type
  17.     Reference AS LONG '  Pointer to hard array index
  18.     North AS LONG '
  19.     South AS LONG '
  20.     East AS LONG '
  21.     West AS LONG '       (Orientation)
  22.  
  23. DIM MaxElements AS INTEGER
  24. MaxElements = 9999
  25.  
  26. ' Element visibility toggle
  27. DIM SHARED IdentityRegister(MaxElements) AS LONG
  28. FOR k = 1 TO UBOUND(IdentityRegister)
  29.     IdentityRegister(k) = 0
  30.  
  31. ' Element storage
  32. DIM SHARED Elements(MaxElements) AS Element
  33.  
  34. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  35. ' Soft Arrays:
  36. '
  37.  
  38. ' Soft array structure
  39. TYPE SoftArrayMeta
  40.     Label AS STRING
  41.     FirstElement AS LONG
  42.  
  43. DIM MaxSoftArrays AS INTEGER
  44. MaxSoftArrays = 99
  45.  
  46. ' Soft array visibility toggle
  47. DIM SHARED SoftArrayRegister(MaxSoftArrays) AS INTEGER
  48. FOR k = 1 TO UBOUND(SoftArrayRegister)
  49.     SoftArrayRegister(k) = 0
  50.  
  51. ' Soft array storage
  52. DIM SHARED SoftArray(MaxSoftArrays) AS SoftArrayMeta
  53.  
  54. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  55. ' Processing
  56. '
  57. DIM SHARED LambdaMatrix(99, 9) AS LONG
  58. DIM SHARED LambdaIndex AS INTEGER
  59. DIM SHARED LambdaArg AS LONG
  60. LambdaIndex = 0
  61. LambdaArg = 0
  62.  
  63. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  64. ' Setup
  65. '
  66.  
  67.  
  68. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  69. ' Main
  70. '
  71.  
  72. CALL DemoArray3D
  73. PRINT "Press any key..."
  74. CALL DemoTree
  75. PRINT "Press any key..."
  76. CALL DemoTreeEdit
  77. PRINT "Press any key..."
  78. CALL DemoArithmetic
  79. PRINT "Press any key..."
  80. CALL DemoList
  81. PRINT "Press any key..."
  82. CALL DemoLambda
  83.  
  84.  
  85. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  86. ' Example cases:
  87. '
  88.  
  89. SUB DemoLambda
  90.     DIM a AS LONG
  91.     DIM b AS LONG
  92.  
  93.     a = NewSoftArray(0, "Lambda Test")
  94.     a = LinkEast(a, NewStringElement("lambda"))
  95.     b = LinkEast(a, NewIntegerElement(4))
  96.     b = LinkSouth(b, NewIntegerElement(6))
  97.     a = LinkSouth(a, NewStringElement("cos"))
  98.     b = LinkEast(a, NewStringElement("*"))
  99.     b = LinkEast(b, NewIntegerElement(3))
  100.     b = LinkSouth(b, NewStringElement("[1]"))
  101.     b = LinkSouth(b, NewIntegerElement(5))
  102.     b = LinkSouth(b, NewStringElement("[2]"))
  103.  
  104.     PRINT PrintSoftArray(ArrayId("Lambda Test"))
  105.     PRINT "..."
  106.     a = Evaluate(FromLabel("Lambda Test"))
  107.     PRINT PrintSoftArray(ArrayId("Lambda Test"))
  108.  
  109. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  110.  
  111. SUB DemoList
  112.     DIM a AS LONG
  113.     DIM b AS LONG
  114.  
  115.     a = NewSoftArray(0, "List Test")
  116.     a = LinkEast(a, NewStringElement("cos"))
  117.     b = LinkEast(a, NewStringElement("three"))
  118.     b = LinkSouth(b, NewStringElement("four"))
  119.     b = LinkSouth(b, NewStringElement("five"))
  120.     b = LinkSouth(b, NewStringElement("six"))
  121.     b = LinkSouth(b, NewStringElement("seven"))
  122.  
  123.     a = LinkSouth(a, NewStringElement("cos"))
  124.     b = LinkEast(a, NewIntegerElement(3))
  125.     b = LinkSouth(b, NewIntegerElement(4))
  126.     b = LinkSouth(b, NewIntegerElement(5))
  127.     b = LinkSouth(b, NewIntegerElement(6))
  128.     b = LinkSouth(b, NewIntegerElement(7))
  129.  
  130.     PRINT PrintSoftArray(ArrayId("List Test"))
  131.     PRINT
  132.     a = Evaluate(FromLabel("List Test"))
  133.     PRINT PrintSoftArray(ArrayId("List Test"))
  134.  
  135. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  136.  
  137. SUB DemoArithmetic
  138.     DIM a AS LONG
  139.     DIM b AS LONG
  140.  
  141.     a = NewSoftArray(0, "Arithmetic Test")
  142.     a = LinkEast(a, NewStringElement("*"))
  143.     b = LinkEast(a, NewIntegerElement(3))
  144.     b = LinkSouth(b, NewIntegerElement(4))
  145.     a = LinkSouth(b, NewStringElement("cos"))
  146.     b = LinkEast(a, NewStringElement("+"))
  147.     b = LinkEast(b, NewIntegerElement(4))
  148.     b = LinkSouth(b, NewIntegerElement(7))
  149.     b = LinkSouth(a, NewIntegerElement(2))
  150.  
  151.     PRINT PrintSoftArray(ArrayId("Arithmetic Test"))
  152.     PRINT
  153.     a = Evaluate(FromLabel("Arithmetic Test"))
  154.     PRINT PrintSoftArray(ArrayId("Arithmetic Test"))
  155.     PRINT
  156.  
  157.     a = NewSoftArray(0, "Arithmetic Test2")
  158.     a = LinkEast(a, NewStringElement("/"))
  159.     b = LinkEast(a, NewIntegerElement(3))
  160.     a = LinkSouth(b, NewStringElement("cos"))
  161.     b = LinkEast(a, NewStringElement("+"))
  162.     b = LinkEast(b, NewIntegerElement(4))
  163.     b = LinkSouth(b, Elements(FromLabel("Arithmetic Test")).East)
  164.  
  165.     PRINT PrintSoftArray(ArrayId("Arithmetic Test2"))
  166.     PRINT
  167.     a = Evaluate(FromLabel("Arithmetic Test2"))
  168.     PRINT PrintSoftArray(ArrayId("Arithmetic Test2"))
  169.  
  170. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  171.  
  172. SUB DemoTreeEdit
  173.     DIM a AS LONG
  174.     DIM b AS LONG
  175.     DIM c AS LONG
  176.  
  177.     a = NewSoftArray(0, "Tree Edit Test")
  178.     a = LinkEast(a, NewStringElement("QB64 Buddy"))
  179.     a = LinkEast(a, NewStringElement("Handle"))
  180.     b = LinkEast(a, NewStringElement("flukiluke"))
  181.     a = LinkSouth(a, NewStringElement("Name"))
  182.     b = LinkEast(a, NewStringElement("Luke C."))
  183.     a = LinkSouth(a, NewStringElement("Country"))
  184.     b = LinkEast(a, NewStringElement("Australia"))
  185.     c = LinkEast(b, NewStringElement("Locality"))
  186.     b = LinkEast(c, NewStringElement("Down Under"))
  187.     a = LinkSouth(a, NewStringElement("Birthyear"))
  188.     b = LinkEast(a, NewIntegerElement(1523))
  189.     c = LinkSouth(b, NewStringElement("May?"))
  190.  
  191.     ' Display and query tests
  192.     PRINT PrintSoftArray(ArrayId("Tree Edit Test"))
  193.     PRINT
  194.  
  195.     PRINT "Inserting `Get it?' into list..."
  196.     a = InsertEast(SeekString("Down Under", FromLabel("Tree Edit Test"), 1), NewStringElement("Get it?"))
  197.     PRINT "Adding new entry to bottom of list..."
  198.     a = InsertSouth(SeekString("QB64 Buddy", FromLabel("Tree Edit Test"), 1), NewStringElement("QB64 Enemy"))
  199.     PRINT "Editing Birthyear..."
  200.     a = EditIntegerReference(StepUsing(SeekString("Birthyear", FromLabel("Tree Edit Test"), 1), "e"), 1855)
  201.     PRINT "Deleting a few entries under Country..."
  202.     a = LinkEast(SeekString("Country", FromLabel("Tree Edit Test"), 1), SeekString("Down Under", FromLabel("Tree Edit Test"), 1))
  203.     PRINT "Unlinking Name..."
  204.     a = Unlink(SeekString("Name", FromLabel("Tree Edit Test"), 1))
  205.  
  206.     PRINT
  207.     PRINT PrintSoftArray(ArrayId("Tree Edit Test"))
  208.  
  209. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  210.  
  211. SUB DemoTree
  212.     DIM a AS LONG
  213.     DIM b AS LONG
  214.     DIM c AS LONG
  215.     DIM d AS LONG
  216.  
  217.     a = NewSoftArray(0, "Tree of Friends")
  218.     a = LinkEast(a, NewStringElement("QB64 Buddy")): d = a
  219.     a = LinkEast(a, NewStringElement("Handle"))
  220.     b = LinkEast(a, NewStringElement("SMcNeill"))
  221.     a = LinkSouth(a, NewStringElement("Name"))
  222.     b = LinkEast(a, NewStringElement("Steve SMcNeill"))
  223.     a = LinkSouth(a, NewStringElement("Country"))
  224.     b = LinkEast(a, NewStringElement("USA"))
  225.     c = LinkEast(b, NewStringElement("Locality"))
  226.     b = LinkEast(c, NewStringElement("Virginia"))
  227.     a = LinkSouth(a, NewStringElement("Birthyear"))
  228.     b = LinkEast(a, NewIntegerElement(1973))
  229.     c = LinkSouth(b, NewStringElement("May?"))
  230.     a = LinkSouth(d, NewStringElement("QB64 Buddy")): d = a
  231.     a = LinkEast(a, NewStringElement("Handle"))
  232.     b = LinkEast(a, NewStringElement("FellippeHeitor"))
  233.     a = LinkSouth(a, NewStringElement("Name"))
  234.     b = LinkEast(a, NewStringElement("Fellippe Heitor"))
  235.     a = LinkSouth(a, NewStringElement("Country"))
  236.     b = LinkEast(a, NewStringElement("Brazil"))
  237.     c = LinkEast(b, NewStringElement("Locality"))
  238.     b = LinkEast(c, NewStringElement("My <3"))
  239.     c = LinkEast(b, NewStringElement("JK, it's ___."))
  240.     a = LinkSouth(a, NewStringElement("Birthyear"))
  241.     b = LinkEast(a, NewIntegerElement(1983))
  242.     c = LinkSouth(b, NewStringElement("Sep?"))
  243.     b = LinkSouth(c, NewStringElement("... or was it May?"))
  244.     a = LinkSouth(d, NewStringElement("QB64 Buddy")): d = a
  245.     a = LinkEast(a, NewStringElement("Handle"))
  246.     b = LinkEast(a, NewStringElement("DanTurtle"))
  247.  
  248.     ' Display array
  249.     PRINT PrintSoftArray(ArrayId("Tree of Friends"))
  250.     PRINT
  251.  
  252.     ' Query tests
  253.     PRINT "Height:"; SquareArrayHeight(ArrayId("Tree of Friends"))
  254.     PRINT "Steve's locality: "; Literal$(StepFromLabel("Tree of Friends", "eesseee"))
  255.     PRINT "Fellippe's locality: "; Literal$(StepFromLabel("Tree of Friends", "esesseee"))
  256.     PRINT "Fellippe's birth month: "; Literal$(StepUsing(JumpFrom(StepFromLabel("Tree of Friends", "ese"), "s", 3), "es"))
  257.     PRINT "Width of Fellippe's Country branch:"; Measure(SeekString("Country", FromLabel("Tree of Friends"), 2), "e")
  258.     PRINT "Height under Fellippe's Birthyear branch:"; Measure(Elements(SeekString("Birthyear", FromLabel("Tree of Friends"), 2)).East, "s")
  259.  
  260. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  261.  
  262. SUB DemoArray3D
  263.     DIM TestArray3D(4, 2, 3) AS STRING
  264.     TestArray3D(1, 1, 1) = "one.one.one"
  265.     TestArray3D(1, 1, 2) = "one.one.two"
  266.     TestArray3D(1, 1, 3) = "one.one.three"
  267.     TestArray3D(1, 2, 1) = "one.two.one"
  268.     TestArray3D(1, 2, 2) = "one.two.two"
  269.     TestArray3D(1, 2, 3) = "one.two.three"
  270.     TestArray3D(2, 1, 1) = "two.one.one"
  271.     TestArray3D(2, 1, 2) = "two.one.two"
  272.     TestArray3D(2, 1, 3) = "two.one.three"
  273.     TestArray3D(2, 2, 1) = "two.two.one"
  274.     TestArray3D(2, 2, 2) = "two.two.two"
  275.     TestArray3D(2, 2, 3) = "two.two.three"
  276.     TestArray3D(3, 1, 1) = "three.one.one"
  277.     TestArray3D(3, 1, 2) = "three.one.two"
  278.     TestArray3D(3, 1, 3) = "three.one.three"
  279.     TestArray3D(3, 2, 1) = "three.two.one"
  280.     TestArray3D(3, 2, 2) = "three.two.two"
  281.     TestArray3D(3, 2, 3) = "three.two.three"
  282.     TestArray3D(4, 1, 1) = "four.one.one"
  283.     TestArray3D(4, 1, 2) = "four.one.two"
  284.     TestArray3D(4, 1, 3) = "four.one.three"
  285.     TestArray3D(4, 2, 1) = "four.two.one"
  286.     TestArray3D(4, 2, 2) = "four.two.two"
  287.     TestArray3D(4, 2, 3) = "four.two.three"
  288.     DIM i AS INTEGER
  289.     DIM j AS INTEGER
  290.     DIM k AS INTEGER
  291.     DIM a AS LONG
  292.     DIM b AS LONG
  293.     a = NewSoftArray(0, "Three-Dimensional Array")
  294.     FOR i = 1 TO UBOUND(TestArray3D, 1)
  295.         FOR j = 1 TO UBOUND(TestArray3D, 2)
  296.             FOR k = 1 TO UBOUND(TestArray3D, 3)
  297.                 IF ((i = 1) AND (j = 1) AND (k = 1)) THEN
  298.                     a = LinkEast(a, NewStringElement(TestArray3D(i, j, k)))
  299.                     b = a
  300.                 ELSE
  301.                     IF (k = 1) THEN
  302.                         a = LinkSouth(a, NewStringElement(TestArray3D(i, j, k)))
  303.                         b = a
  304.                     ELSE
  305.                         b = LinkEast(b, NewStringElement(TestArray3D(i, j, k)))
  306.                     END IF
  307.                 END IF
  308.             NEXT
  309.         NEXT
  310.     NEXT
  311.  
  312.     ' Display array
  313.     PRINT PrintSoftArray(ArrayId("Three-Dimensional Array"))
  314.     PRINT
  315.  
  316.     ' Query tests
  317.     PRINT "Height:"; SquareArrayHeight(ArrayId("Three-Dimensional Array"))
  318.     PRINT "Width:"; SquareArrayWidth(ArrayId("Three-Dimensional Array"))
  319.  
  320. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  321. ' Processing
  322. '
  323.  
  324. FUNCTION Evaluate (x AS LONG)
  325.     DIM TheReturn AS LONG
  326.     DIM a AS LONG
  327.     DIM b AS LONG
  328.     a = x
  329.     b = -1
  330.     DO
  331.         a = EvalStep(FirstEmbedded(a))
  332.         IF (a = x) THEN EXIT DO
  333.         IF (b = a) THEN
  334.             a = Elements(a).South
  335.             IF (a = -1) THEN
  336.                 EXIT DO
  337.             END IF
  338.         ELSE
  339.             b = a
  340.         END IF
  341.     LOOP
  342.     TheReturn = a
  343.     Evaluate = TheReturn
  344.  
  345. FUNCTION EvalStep (x AS LONG)
  346.     DIM TheReturn AS LONG
  347.     DIM SouthernId AS LONG
  348.     DIM NorthernId AS LONG
  349.     DIM FunctionId AS LONG
  350.     DIM i AS LONG
  351.     DIM j AS LONG
  352.     DIM k AS INTEGER
  353.     DIM n AS LONG
  354.     DIM s AS LONG
  355.     DIM RefSpecies AS STRING
  356.     DIM ReturnSpecies AS STRING
  357.     DIM ReturnInteger AS INTEGER
  358.     DIM ReturnString AS STRING
  359.     DIM ReturnDouble AS DOUBLE
  360.     DIM MultiPass AS INTEGER
  361.     RefSpecies = ""
  362.     FunctionId = x
  363.     ReturnSpecies = ""
  364.     ReturnInteger = 0
  365.     ReturnString = ""
  366.     ReturnDouble = 0
  367.  
  368.     ' Pre-evaluation
  369.     IF (x <> -1) THEN
  370.         SouthernId = x
  371.         i = x
  372.         DO
  373.             n = Elements(i).North
  374.             IF (n <> -1) THEN
  375.                 i = n
  376.             ELSE
  377.                 NorthernId = i
  378.                 EXIT DO
  379.             END IF
  380.         LOOP
  381.         FunctionId = Elements(NorthernId).West
  382.         ReturnSpecies = Elements(FunctionId).Species
  383.         SELECT CASE ReturnSpecies
  384.             CASE "integer"
  385.                 ReturnInteger = IntegerData(Elements(FunctionId).Reference)
  386.             CASE "string"
  387.                 ReturnString = StringData(Elements(FunctionId).Reference)
  388.             CASE "double"
  389.                 ReturnDouble = DoubleData(Elements(FunctionId).Reference)
  390.         END SELECT
  391.     END IF
  392.  
  393.     ' Lambda substitution
  394.     i = NorthernId
  395.     DIM lf AS INTEGER
  396.     lf = 0
  397.     DO
  398.         IF (Elements(i).Species = "string") THEN
  399.             IF (StringData(Elements(i).Reference) = "[1]") THEN
  400.                 j = LambdaMatrix(LambdaIndex, 1)
  401.                 Elements(i).Species = Elements(j).Species
  402.                 Elements(i).Reference = Elements(j).Reference
  403.                 lf = 1
  404.             END IF
  405.             IF (StringData(Elements(i).Reference) = "[2]") THEN
  406.                 j = LambdaMatrix(LambdaIndex, 2)
  407.                 Elements(i).Species = Elements(j).Species
  408.                 Elements(i).Reference = Elements(j).Reference
  409.                 lf = 1
  410.             END IF
  411.         END IF
  412.         IF (i = SouthernId) THEN
  413.             EXIT DO
  414.         ELSE
  415.             s = Elements(i).South
  416.             i = s
  417.         END IF
  418.     LOOP
  419.     IF (lf = 1) THEN
  420.         FOR k = 1 TO LambdaArg
  421.             j = Unlink(LambdaMatrix(LambdaIndex, k))
  422.         NEXT
  423.         LambdaIndex = LambdaIndex - 1
  424.     END IF
  425.  
  426.     ' Determine return species
  427.     i = NorthernId
  428.     DO
  429.         IF (i = -1) THEN EXIT DO
  430.         IF (Elements(i).Species = "string") THEN RefSpecies = "string"
  431.         IF ((Elements(i).Species = "double") AND (RefSpecies <> "string")) THEN RefSpecies = "double"
  432.         IF ((Elements(i).Species = "integer") AND (RefSpecies <> "string") AND (RefSpecies <> "double")) THEN RefSpecies = "integer"
  433.         i = Elements(i).South
  434.     LOOP
  435.  
  436.     ' Single-pass evaluation
  437.     MultiPass = 0
  438.     SELECT CASE Literal$(FunctionId)
  439.         CASE "*"
  440.             MultiPass = 1
  441.             ReturnSpecies = RefSpecies
  442.             ReturnInteger = 1
  443.             ReturnDouble = 1
  444.         CASE "+"
  445.             MultiPass = 1
  446.             ReturnSpecies = RefSpecies
  447.             ReturnInteger = 0
  448.             ReturnDouble = 0
  449.         CASE "/"
  450.             MultiPass = 0
  451.             SELECT CASE Elements(NorthernId).Species
  452.                 CASE "integer"
  453.                     ReturnSpecies = "double"
  454.                     SELECT CASE Elements(SouthernId).Species
  455.                         CASE "integer"
  456.                             ReturnDouble = IntegerData(Elements(NorthernId).Reference) / IntegerData(Elements(SouthernId).Reference)
  457.                         CASE "double"
  458.                             ReturnDouble = IntegerData(Elements(NorthernId).Reference) / DoubleData(Elements(SouthernId).Reference)
  459.                     END SELECT
  460.                 CASE "string"
  461.                     ReturnSpecies = "string"
  462.                     ReturnString = Literal$(NorthernId) + "/" + Literal$(SouthernId)
  463.                 CASE "double"
  464.                     ReturnSpecies = "double"
  465.                     SELECT CASE Elements(SouthernId).Species
  466.                         CASE "integer"
  467.                             ReturnDouble = DoubleData(Elements(NorthernId).Reference) / IntegerData(Elements(SouthernId).Reference)
  468.                         CASE "double"
  469.                             ReturnDouble = DoubleData(Elements(NorthernId).Reference) / DoubleData(Elements(SouthernId).Reference)
  470.                     END SELECT
  471.             END SELECT
  472.             i = Unlink(NorthernId)
  473.             i = Unlink(SouthernId)
  474.         CASE "cos"
  475.             IF (NorthernId = SouthernId) THEN
  476.                 MultiPass = 0
  477.                 i = NorthernId
  478.                 SELECT CASE Elements(i).Species
  479.                     CASE "integer"
  480.                         ReturnSpecies = "double"
  481.                         ReturnDouble = COS(IntegerData(Elements(i).Reference))
  482.                     CASE "string"
  483.                         ReturnSpecies = "string"
  484.                         ReturnString = "cos" + "(" + Literal$(i) + ")"
  485.                     CASE "double"
  486.                         ReturnSpecies = "double"
  487.                         ReturnDouble = COS(DoubleData(Elements(i).Reference))
  488.                 END SELECT
  489.                 i = Unlink(i)
  490.             ELSE
  491.                 MultiPass = 1
  492.                 ReturnSpecies = "string"
  493.                 ReturnString = "(" + "cos" + ")"
  494.             END IF
  495.         CASE "lambda"
  496.             MultiPass = 1
  497.             LambdaIndex = LambdaIndex + 1
  498.             ReturnSpecies = "string"
  499.             ReturnString = "(" + "lambda" + ")"
  500.     END SELECT
  501.  
  502.     ' Multi-pass evaluation
  503.     IF (MultiPass = 1) THEN
  504.         i = NorthernId
  505.         DO
  506.             SELECT CASE Literal$(FunctionId)
  507.                 CASE "*"
  508.                     SELECT CASE ReturnSpecies
  509.                         CASE "integer"
  510.                             SELECT CASE Elements(i).Species
  511.                                 CASE "integer"
  512.                                     ReturnInteger = ReturnInteger * IntegerData(Elements(i).Reference)
  513.                                 CASE "double"
  514.                                     ReturnInteger = ReturnInteger * DoubleData(Elements(i).Reference)
  515.                             END SELECT
  516.                         CASE "string"
  517.                             ReturnString = ReturnString + Literal$(i)
  518.                         CASE "double"
  519.                             SELECT CASE Elements(i).Species
  520.                                 CASE "integer"
  521.                                     ReturnDouble = ReturnDouble * IntegerData(Elements(i).Reference)
  522.                                 CASE "double"
  523.                                     ReturnDouble = ReturnDouble * DoubleData(Elements(i).Reference)
  524.                             END SELECT
  525.                     END SELECT
  526.                     IF (i = SouthernId) THEN
  527.                         i = Unlink(i)
  528.                         EXIT DO
  529.                     ELSE
  530.                         s = Elements(i).South
  531.                         i = Unlink(i)
  532.                         i = s
  533.                     END IF
  534.                 CASE "+"
  535.                     SELECT CASE ReturnSpecies
  536.                         CASE "integer"
  537.                             SELECT CASE Elements(i).Species
  538.                                 CASE "integer"
  539.                                     ReturnInteger = ReturnInteger + IntegerData(Elements(i).Reference)
  540.                                 CASE "double"
  541.                                     ReturnInteger = ReturnInteger + DoubleData(Elements(i).Reference)
  542.                             END SELECT
  543.                         CASE "string"
  544.                             ReturnString = ReturnString + Literal$(i)
  545.                         CASE "double"
  546.                             SELECT CASE Elements(i).Species
  547.                                 CASE "integer"
  548.                                     ReturnDouble = ReturnDouble + IntegerData(Elements(i).Reference)
  549.                                 CASE "double"
  550.                                     ReturnDouble = ReturnDouble + DoubleData(Elements(i).Reference)
  551.                             END SELECT
  552.                     END SELECT
  553.                     IF (i = SouthernId) THEN
  554.                         i = Unlink(i)
  555.                         EXIT DO
  556.                     ELSE
  557.                         s = Elements(i).South
  558.                         i = Unlink(i)
  559.                         i = s
  560.                     END IF
  561.                 CASE "cos"
  562.                     SELECT CASE Elements(i).Species
  563.                         CASE "integer"
  564.                             Elements(i).Species = "double"
  565.                             Elements(i).Reference = NewDoubleData(COS(IntegerData(Elements(i).Reference)))
  566.                         CASE "string"
  567.                             Elements(i).Reference = NewStringData("cos" + "(" + Literal$(i) + ")")
  568.                         CASE "double"
  569.                             Elements(i).Species = "double"
  570.                             Elements(i).Reference = NewDoubleData(COS(DoubleData(Elements(i).Reference)))
  571.                     END SELECT
  572.                     IF (i = SouthernId) THEN
  573.                         EXIT DO
  574.                     ELSE
  575.                         s = Elements(i).South
  576.                         i = s
  577.                     END IF
  578.                 CASE "lambda"
  579.                     LambdaArg = LambdaArg + 1
  580.                     LambdaMatrix(LambdaIndex, LambdaArg) = i
  581.                     IF (i = SouthernId) THEN
  582.                         EXIT DO
  583.                     ELSE
  584.                         s = Elements(i).South
  585.                         i = s
  586.                     END IF
  587.             END SELECT
  588.         LOOP
  589.     END IF
  590.  
  591.     Elements(FunctionId).Species = ReturnSpecies
  592.     SELECT CASE ReturnSpecies
  593.         CASE "integer"
  594.             Elements(FunctionId).Reference = NewIntegerData(ReturnInteger)
  595.         CASE "string"
  596.             Elements(FunctionId).Reference = NewStringData(ReturnString)
  597.         CASE "double"
  598.             Elements(FunctionId).Reference = NewDoubleData(ReturnDouble)
  599.     END SELECT
  600.  
  601.     TheReturn = FunctionId
  602.     EvalStep = TheReturn
  603.  
  604. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  605. ' Seek and recall
  606. '
  607.  
  608. FUNCTION FirstEmbedded (x AS LONG)
  609.     DIM TheReturn AS LONG
  610.     TheReturn = MostEmbeddedRecur(x, -1)
  611.     FirstEmbedded = TheReturn
  612.  
  613. FUNCTION MostEmbeddedRecur (x AS LONG, y AS LONG)
  614.     DIM TheReturn AS LONG
  615.     DIM s AS LONG
  616.     DIM e AS LONG
  617.     s = Elements(x).South
  618.     e = Elements(x).East
  619.     IF (e <> -1) THEN
  620.         TheReturn = MostEmbeddedRecur(e, y)
  621.     END IF
  622.     IF (s <> -1) THEN
  623.         TheReturn = MostEmbeddedRecur(s, y)
  624.     END IF
  625.     IF (e = -1) AND (s = -1) AND (y = -1) THEN
  626.         y = x
  627.     END IF
  628.     MostEmbeddedRecur = y
  629.  
  630. FUNCTION ArrayId (x AS STRING)
  631.     DIM TheReturn AS LONG
  632.     DIM k AS LONG
  633.     TheReturn = -1
  634.     FOR k = 1 TO UBOUND(SoftArray)
  635.         IF (SoftArray(k).Label = x) THEN
  636.             TheReturn = k
  637.             EXIT FOR
  638.         END IF
  639.     NEXT
  640.     ArrayId = TheReturn
  641.  
  642. FUNCTION SeekString (t AS STRING, x AS LONG, r AS INTEGER)
  643.     DIM TheReturn AS LONG
  644.     DIM s AS LONG
  645.     DIM e AS LONG
  646.     TheReturn = -1
  647.     s = Elements(x).South
  648.     e = Elements(x).East
  649.     IF (StringData(Elements(x).Reference) = t) THEN
  650.         TheReturn = x
  651.         r = r - 1
  652.     ELSE
  653.         IF (e <> -1) AND (r > 0) THEN
  654.             TheReturn = SeekString(t, e, r)
  655.         END IF
  656.         IF (s <> -1) AND (r > 0) THEN
  657.             TheReturn = SeekString(t, s, r)
  658.         END IF
  659.     END IF
  660.     SeekString = TheReturn
  661.  
  662. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  663. ' Navigation
  664. '
  665.  
  666. FUNCTION FromLabel (x AS STRING)
  667.     DIM TheReturn AS LONG
  668.     TheReturn = SoftArray(ArrayId(x)).FirstElement
  669.     FromLabel = TheReturn
  670.  
  671. FUNCTION StepFromLabel (x AS STRING, t AS STRING)
  672.     DIM TheReturn AS LONG
  673.     TheReturn = StepUsing(FromLabel(x), t)
  674.     StepFromLabel = TheReturn
  675.  
  676. FUNCTION JumpFrom (x AS LONG, t AS STRING, r AS INTEGER)
  677.     DIM TheReturn AS LONG
  678.     TheReturn = x
  679.     IF (r > 0) THEN
  680.         SELECT CASE t
  681.             CASE "n"
  682.                 TheReturn = JumpFrom(Elements(x).North, "n", r - 1)
  683.             CASE "s"
  684.                 TheReturn = JumpFrom(Elements(x).South, "s", r - 1)
  685.             CASE "e"
  686.                 TheReturn = JumpFrom(Elements(x).East, "e", r - 1)
  687.             CASE "w"
  688.                 TheReturn = JumpFrom(Elements(x).West, "w", r - 1)
  689.         END SELECT
  690.     END IF
  691.     JumpFrom = TheReturn
  692.  
  693. FUNCTION StepUsing (x AS LONG, t AS STRING)
  694.     DIM TheReturn AS LONG
  695.     DIM k AS INTEGER
  696.     DIM i AS LONG
  697.     DIM j AS LONG
  698.     i = x
  699.     FOR k = 1 TO LEN(t)
  700.         SELECT CASE MID$(t, k, 1)
  701.             CASE "n"
  702.                 j = Elements(i).North
  703.                 IF (j <> -1) THEN i = j
  704.             CASE "s"
  705.                 j = Elements(i).South
  706.                 IF (j <> -1) THEN i = j
  707.             CASE "e"
  708.                 j = Elements(i).East
  709.                 IF (j <> -1) THEN i = j
  710.             CASE "w"
  711.                 j = Elements(i).West
  712.                 IF (j <> -1) THEN i = j
  713.         END SELECT
  714.     NEXT
  715.     TheReturn = i
  716.     StepUsing = TheReturn
  717.  
  718. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  719. ' Internal metrics
  720. '
  721.  
  722. FUNCTION SquareArrayHeight (x AS INTEGER)
  723.     DIM TheReturn AS INTEGER
  724.     TheReturn = Measure(Elements(SoftArray(x).FirstElement).East, "s")
  725.     SquareArrayHeight = TheReturn
  726.  
  727. FUNCTION SquareArrayWidth (x AS INTEGER)
  728.     DIM TheReturn AS INTEGER
  729.     TheReturn = Measure(Elements(SoftArray(x).FirstElement).East, "e")
  730.     SquareArrayWidth = TheReturn
  731.  
  732. FUNCTION Measure (x AS LONG, t AS STRING)
  733.     DIM TheReturn AS INTEGER
  734.     TheReturn = CountSteps(x, -1, t)
  735.     Measure = TheReturn
  736.  
  737. FUNCTION CountSteps (x AS LONG, y AS LONG, t AS STRING)
  738.     DIM TheReturn AS INTEGER
  739.     DIM k AS LONG
  740.     TheReturn = 0
  741.     SELECT CASE t
  742.         CASE "n"
  743.             k = Elements(x).North
  744.         CASE "s"
  745.             k = Elements(x).South
  746.         CASE "e"
  747.             k = Elements(x).East
  748.         CASE "w"
  749.             k = Elements(x).West
  750.     END SELECT
  751.     IF (k = y) THEN
  752.         TheReturn = TheReturn + 1
  753.     ELSE
  754.         IF (k <> -1) THEN
  755.             TheReturn = TheReturn + 1 + CountSteps(k, y, t)
  756.         END IF
  757.     END IF
  758.     CountSteps = TheReturn
  759.  
  760. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  761. ' Printing and reporting
  762. '
  763.  
  764. FUNCTION PrintSoftArray$ (x AS LONG)
  765.     DIM TheReturn AS STRING
  766.     DIM t AS STRING
  767.     IF (x <> -1) THEN
  768.         t = ListElementsRecur$(0, SoftArray(x).FirstElement)
  769.     END IF
  770.     TheReturn = LEFT$(t, LEN(t) - 1)
  771.     PrintSoftArray = TheReturn
  772.  
  773. FUNCTION ListElementsRecur$ (i AS INTEGER, x AS LONG)
  774.     DIM TheReturn AS STRING
  775.     DIM s AS LONG
  776.     DIM e AS LONG
  777.     s = Elements(x).South
  778.     e = Elements(x).East
  779.     TheReturn = TheReturn + SPACE$(i) + Literal$(x) + CHR$(10)
  780.     IF (e <> -1) THEN
  781.         TheReturn = TheReturn + ListElementsRecur$(i + 2, e)
  782.     END IF
  783.     IF (s <> -1) THEN
  784.         TheReturn = TheReturn + ListElementsRecur$(i, s)
  785.     END IF
  786.     ListElementsRecur$ = TheReturn
  787.  
  788. FUNCTION Literal$ (x AS LONG)
  789.     DIM TheReturn AS STRING
  790.     TheReturn = ""
  791.     IF (x <> -1) THEN
  792.         SELECT CASE Elements(x).Species
  793.             CASE "integer"
  794.                 TheReturn = LTRIM$(RTRIM$(STR$(IntegerData(Elements(x).Reference))))
  795.             CASE "string"
  796.                 TheReturn = StringData(Elements(x).Reference)
  797.             CASE "double"
  798.                 TheReturn = LTRIM$(RTRIM$(STR$(DoubleData(Elements(x).Reference))))
  799.         END SELECT
  800.     END IF
  801.     Literal$ = TheReturn
  802.  
  803. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  804. ' Soft array construction
  805. '
  806.  
  807. FUNCTION NextOpenSoftArray (x AS LONG)
  808.     DIM TheReturn AS LONG
  809.     DIM k AS LONG
  810.     TheReturn = -1
  811.     FOR k = x TO UBOUND(SoftArrayRegister)
  812.         IF (SoftArrayRegister(k) = 0) THEN
  813.             TheReturn = k
  814.             EXIT FOR
  815.         END IF
  816.     NEXT
  817.     NextOpenSoftArray = TheReturn
  818.  
  819. FUNCTION NewSoftArray (i AS INTEGER, t AS STRING)
  820.     DIM k AS LONG
  821.     k = NewStringElement(t)
  822.     IF (i < 1) THEN
  823.         i = NextOpenSoftArray(1)
  824.         SoftArrayRegister(i) = i
  825.     END IF
  826.     SoftArray(i).Label = StringData(Elements(k).Reference)
  827.     SoftArray(i).FirstElement = k
  828.     NewSoftArray = k
  829.  
  830. FUNCTION LinkSouth (n AS LONG, s AS LONG)
  831.     DIM TheReturn AS LONG
  832.     Elements(s).North = n
  833.     Elements(n).South = s
  834.     TheReturn = s
  835.     LinkSouth = TheReturn
  836.  
  837. FUNCTION LinkEast (w AS LONG, e AS LONG)
  838.     DIM TheReturn AS LONG
  839.     Elements(w).East = e
  840.     Elements(e).West = w
  841.     TheReturn = e
  842.     LinkEast = TheReturn
  843.  
  844. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  845. ' Soft array editing
  846. '
  847. FUNCTION InsertSouth (n AS LONG, x AS LONG)
  848.     DIM s AS LONG
  849.     s = Elements(n).South
  850.     Elements(n).South = x
  851.     Elements(x).North = n
  852.     Elements(x).South = s
  853.     IF (s <> -1) THEN
  854.         Elements(s).North = x
  855.     END IF
  856.     InsertSouth = x
  857.  
  858. FUNCTION InsertEast (w AS LONG, x AS LONG)
  859.     DIM e AS LONG
  860.     e = Elements(w).East
  861.     Elements(w).East = x
  862.     Elements(x).West = w
  863.     Elements(x).East = e
  864.     IF (e <> -1) THEN
  865.         Elements(e).West = x
  866.     END IF
  867.     InsertEast = x
  868.  
  869. FUNCTION Unlink (x AS LONG)
  870.     DIM n AS LONG
  871.     DIM s AS LONG
  872.     DIM e AS LONG
  873.     DIM w AS LONG
  874.     n = Elements(x).North
  875.     s = Elements(x).South
  876.     e = Elements(x).East
  877.     w = Elements(x).West
  878.     IF (n <> -1) THEN Elements(n).South = s
  879.     IF (s <> -1) THEN Elements(s).North = n
  880.     IF (e <> -1) THEN Elements(e).West = w
  881.     IF (w <> -1) THEN Elements(w).East = e
  882.     IdentityRegister(x) = 0
  883.     Unlink = x
  884.  
  885. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  886. ' Element creation
  887. '
  888.  
  889. FUNCTION NextOpenIdentity (x AS LONG)
  890.     DIM TheReturn AS LONG
  891.     DIM k AS LONG
  892.     TheReturn = -1
  893.     FOR k = x TO UBOUND(IdentityRegister)
  894.         IF (IdentityRegister(k) = 0) THEN
  895.             TheReturn = k
  896.             EXIT FOR
  897.         END IF
  898.     NEXT
  899.     NextOpenIdentity = TheReturn
  900.  
  901. FUNCTION NewElement (x AS LONG, t AS STRING, r AS LONG)
  902.     DIM i AS LONG
  903.     i = NextOpenIdentity(x)
  904.     IdentityRegister(i) = i
  905.     Elements(i).Identity = i
  906.     Elements(i).Species = t
  907.     Elements(i).Reference = r
  908.     Elements(i).North = -1
  909.     Elements(i).South = -1
  910.     Elements(i).East = -1
  911.     Elements(i).West = -1
  912.     NewElement = i
  913.  
  914. FUNCTION NewIntegerElement (x AS INTEGER)
  915.     NewIntegerElement = NewElement(1, "integer", NewIntegerData(x))
  916.  
  917. FUNCTION NewStringElement (x AS STRING)
  918.     NewStringElement = NewElement(1, "string", NewStringData(x))
  919.  
  920. FUNCTION NewDoubleElement (x AS DOUBLE)
  921.     NewDoubleElement = NewElement(1, "double", NewDoubleData(x))
  922.  
  923. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  924. ' Element editing
  925. '
  926.  
  927. FUNCTION EditIntegerReference (i AS LONG, x AS INTEGER)
  928.     DIM z AS LONG
  929.     z = NewIntegerData(x)
  930.     Elements(i).Reference = z
  931.     EditIntegerReference = z
  932.  
  933. FUNCTION EditStringReference (i AS LONG, x AS STRING)
  934.     DIM z AS LONG
  935.     z = NewStringData(x)
  936.     Elements(i).Reference = z
  937.     EditStringReference = z
  938.  
  939. FUNCTION EditDoubleReference (i AS LONG, x AS DOUBLE)
  940.     DIM z AS LONG
  941.     z = NewDoubleData(x)
  942.     Elements(i).Reference = z
  943.     EditDoubleReference = z
  944.  
  945. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  946. ' Data assimilation
  947. '
  948.  
  949. FUNCTION NewIntegerData (x AS INTEGER)
  950.     DIM TheReturn AS LONG
  951.     DIM k AS LONG
  952.     TheReturn = -1
  953.     FOR k = 1 TO UBOUND(IntegerData)
  954.         IF (IntegerData(k) = x) THEN
  955.             TheReturn = k
  956.             EXIT FOR
  957.         END IF
  958.     NEXT
  959.     IF (TheReturn = -1) THEN
  960.         REDIM _PRESERVE IntegerData(UBOUND(IntegerData) + 1)
  961.         IntegerData(UBOUND(IntegerData)) = x
  962.         TheReturn = UBOUND(IntegerData)
  963.     END IF
  964.     NewIntegerData = TheReturn
  965.  
  966. FUNCTION NewStringData (x AS STRING)
  967.     DIM TheReturn AS LONG
  968.     DIM k AS LONG
  969.     TheReturn = -1
  970.     FOR k = 1 TO UBOUND(StringData)
  971.         IF (StringData(k) = x) THEN
  972.             TheReturn = k
  973.             EXIT FOR
  974.         END IF
  975.     NEXT
  976.     IF (TheReturn = -1) THEN
  977.         REDIM _PRESERVE StringData(UBOUND(StringData) + 1)
  978.         StringData(UBOUND(Stringdata)) = x
  979.         TheReturn = UBOUND(StringData)
  980.     END IF
  981.     NewStringData = TheReturn
  982.  
  983. FUNCTION NewDoubleData (x AS DOUBLE)
  984.     DIM TheReturn AS LONG
  985.     DIM k AS LONG
  986.     TheReturn = -1
  987.     FOR k = 1 TO UBOUND(DoubleData)
  988.         IF (DoubleData(k) = x) THEN
  989.             TheReturn = k
  990.             EXIT FOR
  991.         END IF
  992.     NEXT
  993.     IF (TheReturn = -1) THEN
  994.         REDIM _PRESERVE DoubleData(UBOUND(DoubleData) + 1)
  995.         DoubleData(UBOUND(DoubleData)) = x
  996.         TheReturn = UBOUND(DoubleData)
  997.     END IF
  998.     NewDoubleData = TheReturn
  999.  
ss.png
* ss.png (Filesize: 31.34 KB, Dimensions: 814x627, Views: 209)
You're not done when it works, you're done when it's right.

FellippeHeitor

  • Guest
Re: A new take on arrays and data
« Reply #17 on: April 12, 2020, 09:20:19 am »
Allow me to pour some stupidity into this otherwise math superior thread. You know how much I respect you and how aware I am of your love for the topic, but this has now popped in my head:

For languages that do allow lambda/anonymous functions: what'd be the use of:

Code: QB64: [Select]
  1.  PRINT {COS(3*x*5*y)} (4,6)

...if it'll never be reused? My QBrain wants to simply:

Code: QB64: [Select]
  1.  PRINT COS(3*4*5*6)

This is an honest question.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #18 on: April 12, 2020, 09:30:18 am »
Damn I can answer this in spades if it werent for me heading to a nursing home to solve a drain problem.

For now, and this is kind of occult knowledge, but try to imagine when I've used the dollar sign in sxript- it's the same thing used there
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #19 on: April 12, 2020, 10:53:31 pm »
Alrighty, so Fellippe's question was more-or-less handled on Discord, but a public question still deserves some kind of public answer.

As I mentioned earlier,
Quote
...this stuff has much more power when your surrounding paradigm leans functional, meaning functions and code are passed around as data. I know that sounds weird, and I'm afraid I won't try to justify it in this paragraph.

I guess I need to justify it in *this* paragraph. The real problem is these concepts can't be taken in isolation - so here comes yet another mouthful. The example language I'm using is Sxript for non-self-serving reasons... It turns out QB64 has no analog for the stuff that follows...

High Order Function

So first we need a high-order function. These can be thought of as functions that have no distinct job until called with special arguments. The arguments need to somehow contain *code*, which sounds weird as hell a QB64 coder. The high-order function we'll use is extremely simple:

Code: [Select]
func(DoSomething,{[x]([y])})
Inside the curly braces, you see the very simple form x(y). This means the DoSomething function can take *any* two arguments x, y as long as the resulting statement makes sense. For example, these lines

Code: [Select]
DoSomething(cos,3)

DoSomething(sin,3)

... are immediately translated to cos(3) and sin(3). Everyone with me?

Anonymous Function

Now we may ask, "what if the x-argument I send to DoSomething isn't a named function"? That is, suppose we want to calculate cos(3)+sin(3). Of course, you're totally allowed to write

Code: [Select]
func(cosplussin,{cos([x])+sin([x])})

DoSomething(cosplussin,3)

... which is totally fine... but the new argument is: why name the function if we're only using it once? Or - can the above be done in one line? Yes, that's where the anonymous function steps in:

Code: [Select]
DoSomething($({sin([x])+cos([x])}),3)
There you can see the guts of the function, even contained in curly braces, but we never named the function. This is what's going on in the latest update to the Soft Arrays code.

Code as Data

I can still hear it though: that question "why not just hardcode the one-liner, with or without a function?"... This question is brilliantly met with the idea of code as data. Consider the following Sxript line:

Code: [Select]
let(a, {[x]+tan([x])} )
Here we have a variable, not a function, that contains the instruction x+tan(x). Note now that the content of the curly braces could be made by ANY process - ask the user to type a function, piece one together from other snippets, etc. - point is, you can do anything you want to build the contents of let(a, {...} ). This is the idea behind code as data. The advantage? Send it right to your high-order function as an anonymous function:

Code: [Select]
DoSomething($([a]),3)
Conclusion

Forgive my sloppy introduction to functional programming concepts if you've already heard of this stuff. If not though, consider yourself led to water!

The full code I was working with is right here:

Code: [Select]
func(DoSomething,{[x]([y])})                      :
print_DoSomething(cos,3)                         ,:
print_DoSomething(sin,3)                         ,:
print_DoSomething($({sin([x])+cos([x])}),3)      ,:
let(a, {[x]+tan([x])} )                           :
print_DoSomething($([a]),3)                      ,:

... which can be pasted into the console at http://barnes.x10host.com/sxript/docs/console/console.html to see it work.
You're not done when it works, you're done when it's right.

FellippeHeitor

  • Guest
Re: A new take on arrays and data
« Reply #20 on: April 12, 2020, 11:09:04 pm »
Thanks, man. Nicely put.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #21 on: April 19, 2020, 10:45:48 am »
Alright, this update was far harder to churn out, namely from getting lost in my own notation because I still work in the trenches 60 hours a week. Lockdown? What lockdown...?

I should also apologize for not responding to data-related discussions on adjacent threads, which transitions into today's update. Rather than wax poetic about the recent streamlining, I decided to code a visual component to this code base. Don't worry - it's still layered properly and the graphics are in no way essential to anything - it's pure sugar.

This can be taken in any number of directions, which is why it's the perfect place to stop. From the demos below, I hope you can see this code going in the direction of databases, list processing, (god willing) a LISP-like scripting language, etc. etc. etc. Rather than pursue any of those, I think it'll be best to package this code as a plug-n-play library that can stand in for regular arrays when your data becomes less linear.

For now though, just press enter to sail through each demo - there's nothing else to do.

Code: QB64: [Select]
  1. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2. ' Meta:
  3. '
  4.  
  5.  
  6. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  7. ' Begin BI-component.
  8. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  9.  
  10. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  11. ' Hard arrays to store actual data:
  12. '
  13. REDIM SHARED IntegerData(0) AS INTEGER
  14. REDIM SHARED StringData(0) AS STRING
  15. REDIM SHARED DoubleData(0) AS DOUBLE
  16.  
  17. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  18. ' Temp variable(s):
  19. '
  20.  
  21.  
  22. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  23. ' Nodes:
  24. '
  25.  
  26. ' Node structure
  27. TYPE Node
  28.     Identity AS LONG '   Address in identity register
  29.     Species AS STRING '  Data type
  30.     Reference AS LONG '  Pointer to hard array index
  31.     North AS LONG '
  32.     South AS LONG '
  33.     East AS LONG '
  34.     West AS LONG '       (Orientation)
  35.  
  36. DIM MaxNodes AS INTEGER
  37. MaxNodes = 9999
  38.  
  39. ' Node visibility toggle
  40. DIM SHARED IdentityRegister(MaxNodes) AS LONG
  41. FOR k = 1 TO UBOUND(IdentityRegister)
  42.     IdentityRegister(k) = 0
  43.  
  44. ' Node storage
  45. DIM SHARED Nodes(MaxNodes) AS Node
  46.  
  47. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  48. ' Linked lists:
  49. '
  50.  
  51. ' Linked list structure
  52. TYPE LinkedListStructure
  53.     Label AS STRING
  54.     FirstNode AS LONG
  55.  
  56. DIM MaxLinkedLists AS INTEGER
  57. MaxLinkedLists = 99
  58.  
  59. ' Linked list visibility toggle
  60. DIM SHARED LinkedListRegister(MaxLinkedLists) AS INTEGER
  61. FOR k = 1 TO UBOUND(LinkedListRegister)
  62.     LinkedListRegister(k) = 0
  63.  
  64. ' Linked list storage
  65. DIM SHARED LinkedList(MaxLinkedLists) AS LinkedListStructure
  66.  
  67. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  68. ' Processing
  69. '
  70. DIM SHARED LambdaMatrix(99, 9) AS LONG
  71. DIM SHARED LambdaIndex AS INTEGER
  72. DIM SHARED LambdaArgCount(9) AS LONG
  73. LambdaIndex = 0
  74.  
  75. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  76. ' End BI-component.
  77. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  78.  
  79. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  80. ' Pre-Main
  81. '
  82.  
  83. SCREEN _NEWIMAGE(800, 600, 32)
  84.  
  85. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  86. ' Visual Nodes (OPTIONAL)
  87. '
  88.  
  89. TYPE Vector
  90.     x AS DOUBLE
  91.     y AS DOUBLE
  92.  
  93. ' Visual node structure
  94. TYPE VisualNodesStructure
  95.     Reference AS LONG '    Points to a node.
  96.     BoxCenter AS Vector
  97.     BoxHeight AS DOUBLE
  98.     BoxWidth AS DOUBLE
  99.     CornerNE AS Vector
  100.     CornerNW AS Vector
  101.     CornerSE AS Vector
  102.     CornerSW AS Vector
  103.     AntennaN AS Vector
  104.     AntennaS AS Vector
  105.     AntennaE AS Vector
  106.     AntennaW AS Vector
  107.  
  108. DIM MaxVisualNodess AS INTEGER
  109. DIM SHARED VisualNodesCount AS INTEGER
  110. MaxVisualNodess = 256
  111. VisualNodesCount = 0
  112.  
  113. ' Visual node storage
  114. DIM SHARED VisualNodes(MaxVisualNodess) AS VisualNodesStructure
  115.  
  116. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  117. ' Main
  118. '
  119.  
  120. '
  121. CALL DemoArray3D
  122. '
  123. CALL DemoTree
  124. '
  125. CALL DemoTreeEdit
  126. '
  127. CALL DemoArithmetic
  128. '
  129. CALL DemoList
  130. '
  131. CALL DemoLambda
  132. '
  133. CALL DemoMerge
  134. '
  135.  
  136.  
  137.  
  138. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  139. ' Visual Node graphics (OPTIONAL)
  140. '
  141.  
  142. SUB ReportVisualNodes (x AS LONG, x0 AS DOUBLE, y0 AS DOUBLE)
  143.     DIM k AS INTEGER
  144.     PRINT PrintLinkedList$(Literal$(x))
  145.     VisualNodesCount = 0
  146.     CALL VisualListRecur(x, x0, y0)
  147.     FOR k = 1 TO VisualNodesCount
  148.         CALL DrawWires(k)
  149.         CALL DrawVisualNode(k)
  150.     NEXT
  151.  
  152. SUB VisualListRecur (x AS LONG, x0 AS DOUBLE, y0 AS DOUBLE)
  153.     DIM s AS LONG
  154.     DIM e AS LONG
  155.     s = Nodes(x).South
  156.     e = Nodes(x).East
  157.     VisualNodesCount = VisualNodesCount + 1
  158.     CALL DefineVisualNode(VisualNodesCount, x, x0, y0)
  159.     y0 = y0 - 30
  160.     IF (e <> -1) THEN
  161.         CALL VisualListRecur(e, x0 + 25, y0)
  162.     END IF
  163.     IF (s <> -1) THEN
  164.         CALL VisualListRecur(s, x0, y0)
  165.     END IF
  166.  
  167. SUB DefineVisualNode (i AS INTEGER, x AS LONG, x0 AS DOUBLE, y0 AS DOUBLE)
  168.     DIM cx AS DOUBLE
  169.     DIM cy AS DOUBLE
  170.     DIM h AS DOUBLE
  171.     DIM w AS DOUBLE
  172.     cx = x0
  173.     cy = y0
  174.     h = 22
  175.     w = 12 + 8 * LEN(Literal$(x))
  176.     VisualNodes(i).Reference = x
  177.     VisualNodes(i).BoxCenter.x = cx
  178.     VisualNodes(i).BoxCenter.y = cy
  179.     VisualNodes(i).BoxHeight = h
  180.     VisualNodes(i).BoxWidth = w
  181.     VisualNodes(i).CornerNE.x = cx + .5 * w
  182.     VisualNodes(i).CornerNE.y = cy + .5 * h
  183.     VisualNodes(i).CornerNW.x = cx - .5 * w
  184.     VisualNodes(i).CornerNW.y = cy + .5 * h
  185.     VisualNodes(i).CornerSE.x = cx + .5 * w
  186.     VisualNodes(i).CornerSE.y = cy - .5 * h
  187.     VisualNodes(i).CornerSW.x = cx - .5 * w
  188.     VisualNodes(i).CornerSW.y = cy - .5 * h
  189.     VisualNodes(i).AntennaN.x = cx
  190.     VisualNodes(i).AntennaN.y = cy + .5 * h + 3
  191.     VisualNodes(i).AntennaS.x = cx
  192.     VisualNodes(i).AntennaS.y = cy - .5 * h - 3
  193.     VisualNodes(i).AntennaE.x = cx + .5 * w + 3
  194.     VisualNodes(i).AntennaE.y = cy
  195.     VisualNodes(i).AntennaW.x = cx - .5 * w - 3
  196.     VisualNodes(i).AntennaW.y = cy
  197.  
  198. SUB DrawVisualNode (x AS LONG)
  199.     CALL clineb(VisualNodes(x).CornerNE.x, VisualNodes(x).CornerNE.y, VisualNodes(x).CornerSW.x, VisualNodes(x).CornerSW.y, _RGB32(255, 255, 255))
  200.     CALL cprintstring(VisualNodes(x).CornerNW.x + 8, VisualNodes(x).CornerNW.y - 4, Literal$(VisualNodes(x).Reference))
  201.  
  202. FUNCTION VisualNodeIndexFromReference (x AS LONG)
  203.     DIM TheReturn AS INTEGER
  204.     DIM j AS INTEGER
  205.     TheReturn = -1
  206.     FOR j = 1 TO VisualNodesCount
  207.         IF (VisualNodes(j).Reference = x) THEN
  208.             TheReturn = j
  209.             EXIT FOR
  210.         END IF
  211.     NEXT
  212.     VisualNodeIndexFromReference = TheReturn
  213.  
  214. SUB DrawWires (x AS INTEGER)
  215.     DIM i AS LONG
  216.     DIM k AS INTEGER
  217.     DIM s AS LONG
  218.     DIM e AS LONG
  219.     i = VisualNodes(x).Reference
  220.     s = Nodes(i).South
  221.     e = Nodes(i).East
  222.     IF (s <> -1) THEN
  223.         k = VisualNodeIndexFromReference(s)
  224.         CALL cline(VisualNodes(x).AntennaS.x, VisualNodes(x).AntennaS.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGB32(255, 255, 255))
  225.         CALL ccircle(VisualNodes(x).AntennaS.x, VisualNodes(x).AntennaS.y, 3, _RGB32(255, 255, 255))
  226.     END IF
  227.     IF (e <> -1) THEN
  228.         k = VisualNodeIndexFromReference(e)
  229.         CALL cline(VisualNodes(x).AntennaE.x, VisualNodes(x).AntennaE.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGB32(255, 255, 255))
  230.         CALL ccircle(VisualNodes(x).AntennaE.x, VisualNodes(x).AntennaE.y, 3, _RGB32(255, 255, 255))
  231.     END IF
  232.  
  233. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  234. ' Cartesian graphics
  235. '
  236.  
  237. SUB cline (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  238.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2, -y2 + _HEIGHT / 2), col
  239.  
  240. SUB clineb (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  241.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2, -y2 + _HEIGHT / 2), col, B
  242.  
  243. SUB ccircle (x1 AS DOUBLE, y1 AS DOUBLE, rad AS DOUBLE, col AS _UNSIGNED LONG)
  244.     CIRCLE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), rad, col
  245.  
  246. SUB cpset (x1 AS DOUBLE, y1 AS DOUBLE, col AS _UNSIGNED LONG)
  247.     PSET (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), col
  248.  
  249. SUB cpaint (x1 AS DOUBLE, y1 AS DOUBLE, col1 AS _UNSIGNED LONG, col2 AS _UNSIGNED LONG)
  250.     PAINT (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), col1, col2
  251.  
  252. SUB cprintstring (x1 AS DOUBLE, y1 AS DOUBLE, a AS STRING)
  253.     '_PRINTSTRING (_WIDTH / 2 - (LEN(a) * 8) / 2, -y + _HEIGHT / 2), a
  254.     _PRINTSTRING (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), a
  255.  
  256. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  257. ' Demo cases:
  258. '
  259.  
  260. SUB DemoMerge
  261.     DIM a AS LONG
  262.     DIM b AS LONG
  263.     a = NewLinkedList("top part")
  264.     a = LinkEast(a, NewStringNode("lambda"))
  265.     b = LinkEast(a, NewIntegerNode(4))
  266.     b = LinkSouth(b, NewIntegerNode(6))
  267.     a = NewUnitList("cow", NewIntegerNode(5))
  268.     a = NewLinkedList("bottom part")
  269.     a = LinkEast(a, NewStringNode("cos"))
  270.     b = LinkEast(a, NewStringNode("*"))
  271.     b = LinkEast(b, NewIntegerNode(3))
  272.     b = LinkSouth(b, NewStringNode("[1]"))
  273.     b = LinkSouth(b, NewIntegerNode(IntegerData(Nodes(Nodes(FirstFromLabel("cow")).East).Reference)))
  274.     b = LinkSouth(b, NewStringNode("[2]"))
  275.  
  276.     CALL ReportVisualNodes(FirstFromLabel("top part"), 0, .9 * _HEIGHT / 2):
  277.     CALL ReportVisualNodes(FirstFromLabel("bottom part"), 0, 0):
  278.     PRINT: PRINT "Press any key...": SLEEP: CLS
  279.  
  280.     a = ListId("bottom part")
  281.     b = LinkedList(a).FirstNode
  282.     LinkedListRegister(a) = 0
  283.     IdentityRegister(b) = 0
  284.  
  285.     a = Nodes(LinkedList(ListId("top part")).FirstNode).East
  286.     b = Nodes(b).East
  287.     Nodes(b).North = a
  288.     Nodes(a).South = b
  289.  
  290.     CALL ReportVisualNodes(FirstFromLabel("top part"), 0, .9 * _HEIGHT / 2)
  291.     PRINT: PRINT "Press any key...": SLEEP: CLS
  292.  
  293.     a = Evaluate(FirstFromLabel("top part"))
  294.  
  295.     CALL ReportVisualNodes(FirstFromLabel("top part"), 0, .9 * _HEIGHT / 2)
  296.     PRINT: PRINT "Press any key...": SLEEP: CLS
  297.  
  298. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  299.  
  300. SUB DemoLambda
  301.     DIM a AS LONG
  302.     DIM b AS LONG
  303.     a = NewUnitList("cow", NewIntegerNode(5))
  304.     a = NewLinkedList("Lambda Test")
  305.     a = LinkEast(a, NewStringNode("lambda"))
  306.     b = LinkEast(a, NewIntegerNode(4))
  307.     b = LinkSouth(b, NewIntegerNode(6))
  308.     a = LinkSouth(a, NewStringNode("cos"))
  309.     b = LinkEast(a, NewStringNode("*"))
  310.     b = LinkEast(b, NewIntegerNode(3))
  311.     b = LinkSouth(b, NewStringNode("[1]"))
  312.     b = LinkSouth(b, NewIntegerNode(IntegerData(Nodes(Nodes(FirstFromLabel("cow")).East).Reference)))
  313.     b = LinkSouth(b, NewStringNode("[2]"))
  314.  
  315.     CALL ReportVisualNodes(FirstFromLabel("Lambda Test"), 0, .9 * _HEIGHT / 2)
  316.     PRINT: PRINT "Press any key...": SLEEP: CLS
  317.  
  318.     a = Evaluate(FirstFromLabel("Lambda Test"))
  319.  
  320.     CALL ReportVisualNodes(FirstFromLabel("Lambda Test"), 0, .9 * _HEIGHT / 2)
  321.     PRINT: PRINT "Press any key...": SLEEP: CLS
  322.  
  323. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  324.  
  325. SUB DemoList
  326.     DIM a AS LONG
  327.     DIM b AS LONG
  328.     a = NewLinkedList("List Test")
  329.     a = LinkEast(a, NewStringNode("cos"))
  330.     b = LinkEast(a, NewStringNode("three"))
  331.     b = LinkSouth(b, NewStringNode("four"))
  332.     b = LinkSouth(b, NewStringNode("five"))
  333.     b = LinkSouth(b, NewStringNode("six"))
  334.     b = LinkSouth(b, NewStringNode("seven"))
  335.     a = LinkSouth(a, NewStringNode("cos"))
  336.     b = LinkEast(a, NewIntegerNode(3))
  337.     b = LinkSouth(b, NewIntegerNode(4))
  338.     b = LinkSouth(b, NewIntegerNode(5))
  339.     b = LinkSouth(b, NewIntegerNode(6))
  340.     b = LinkSouth(b, NewIntegerNode(7))
  341.  
  342.     CALL ReportVisualNodes(FirstFromLabel("List Test"), 0, .9 * _HEIGHT / 2)
  343.     PRINT: PRINT "Press any key...": SLEEP: CLS
  344.  
  345.     a = Evaluate(FirstFromLabel("List Test"))
  346.  
  347.     CALL ReportVisualNodes(FirstFromLabel("List Test"), 0, .9 * _HEIGHT / 2)
  348.     PRINT: PRINT "Press any key...": SLEEP: CLS
  349.  
  350.  
  351. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  352.  
  353. SUB DemoArithmetic
  354.     DIM a AS LONG
  355.     DIM b AS LONG
  356.     a = NewLinkedList("Arithmetic Test")
  357.     a = LinkEast(a, NewStringNode("*"))
  358.     b = LinkEast(a, NewIntegerNode(3))
  359.     b = LinkSouth(b, NewIntegerNode(4))
  360.     a = LinkSouth(b, NewStringNode("cos"))
  361.     b = LinkEast(a, NewStringNode("+"))
  362.     b = LinkEast(b, NewIntegerNode(4))
  363.     b = LinkSouth(b, NewIntegerNode(7))
  364.     b = LinkSouth(a, NewIntegerNode(2))
  365.  
  366.     CALL ReportVisualNodes(FirstFromLabel("Arithmetic Test"), 0, .9 * _HEIGHT / 2)
  367.     PRINT: PRINT "Press any key...": SLEEP: CLS
  368.  
  369.     a = Evaluate(FirstFromLabel("Arithmetic Test"))
  370.  
  371.     CALL ReportVisualNodes(FirstFromLabel("Arithmetic Test"), 0, .9 * _HEIGHT / 2)
  372.     PRINT: PRINT "Press any key...": SLEEP: CLS
  373.  
  374.     a = NewLinkedList("Arithmetic Test2")
  375.     a = LinkEast(a, NewStringNode("/"))
  376.     b = LinkEast(a, NewIntegerNode(3))
  377.     a = LinkSouth(b, NewStringNode("cos"))
  378.     b = LinkEast(a, NewStringNode("+"))
  379.     b = LinkEast(b, NewIntegerNode(4))
  380.     b = LinkSouth(b, NewDoubleNode(DoubleData(Nodes(Nodes(FirstFromLabel("Arithmetic Test")).East).Reference)))
  381.  
  382.     CALL ReportVisualNodes(FirstFromLabel("Arithmetic Test2"), 0, .9 * _HEIGHT / 2)
  383.     PRINT: PRINT "Press any key...": SLEEP: CLS
  384.  
  385.     a = Evaluate(FirstFromLabel("Arithmetic Test2"))
  386.  
  387.     CALL ReportVisualNodes(FirstFromLabel("Arithmetic Test2"), 0, .9 * _HEIGHT / 2)
  388.     PRINT: PRINT "Press any key...": SLEEP: CLS
  389.  
  390. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  391.  
  392. SUB DemoTreeEdit
  393.     DIM a AS LONG
  394.     DIM b AS LONG
  395.     DIM c AS LONG
  396.     a = NewLinkedList("Tree Edit Test")
  397.     a = LinkEast(a, NewStringNode("QB64 Buddy"))
  398.     a = LinkEast(a, NewStringNode("Handle"))
  399.     b = LinkEast(a, NewStringNode("flukiluke"))
  400.     a = LinkSouth(a, NewStringNode("Name"))
  401.     b = LinkEast(a, NewStringNode("Luke C."))
  402.     a = LinkSouth(a, NewStringNode("Country"))
  403.     b = LinkEast(a, NewStringNode("Australia"))
  404.     c = LinkEast(b, NewStringNode("Locality"))
  405.     b = LinkEast(c, NewStringNode("Down Under"))
  406.     a = LinkSouth(a, NewStringNode("Birthyear"))
  407.     b = LinkEast(a, NewIntegerNode(1523))
  408.     c = LinkSouth(b, NewStringNode("May???"))
  409.  
  410.     CALL ReportVisualNodes(FirstFromLabel("Tree Edit Test"), 0, .9 * _HEIGHT / 2)
  411.     PRINT: PRINT "Press any key...": SLEEP: CLS
  412.  
  413.     PRINT "Inserting `Get it?' into list..."
  414.     a = InsertEast(SeekString("Down Under", FirstFromLabel("Tree Edit Test"), 1), NewStringNode("Get it?"))
  415.     PRINT "Adding new entry to bottom of list..."
  416.     a = InsertSouth(SeekString("QB64 Buddy", FirstFromLabel("Tree Edit Test"), 1), NewStringNode("QB64 Enemy"))
  417.     PRINT "Editing Birthyear..."
  418.     a = EditIntegerReference(StepUsing(SeekString("Birthyear", FirstFromLabel("Tree Edit Test"), 1), "e"), 1855)
  419.     PRINT "Deleting a few entries under Country..."
  420.     a = LinkEast(SeekString("Country", FirstFromLabel("Tree Edit Test"), 1), SeekString("Down Under", FirstFromLabel("Tree Edit Test"), 1))
  421.     PRINT "Unlinking Name..."
  422.     a = Unlink(SeekString("Name", FirstFromLabel("Tree Edit Test"), 1))
  423.     PRINT
  424.  
  425.     CALL ReportVisualNodes(FirstFromLabel("Tree Edit Test"), 0, .9 * _HEIGHT / 2)
  426.     PRINT: PRINT "Press any key...": SLEEP: CLS
  427.  
  428. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  429.  
  430. SUB DemoTree
  431.     DIM a AS LONG
  432.     DIM b AS LONG
  433.     DIM c AS LONG
  434.     DIM d AS LONG
  435.     a = NewLinkedList("Tree of Friends")
  436.     a = LinkEast(a, NewStringNode("QB64 Buddy")): d = a
  437.     a = LinkEast(a, NewStringNode("Handle"))
  438.     b = LinkEast(a, NewStringNode("SMcNeill"))
  439.     a = LinkSouth(a, NewStringNode("Name"))
  440.     b = LinkEast(a, NewStringNode("Steve SMcNeill"))
  441.     a = LinkSouth(a, NewStringNode("Country"))
  442.     b = LinkEast(a, NewStringNode("USA"))
  443.     c = LinkEast(b, NewStringNode("Locality"))
  444.     b = LinkEast(c, NewStringNode("Virginia"))
  445.     a = LinkSouth(a, NewStringNode("Birthyear"))
  446.     b = LinkEast(a, NewIntegerNode(1973))
  447.     c = LinkSouth(b, NewStringNode("May?"))
  448.     a = LinkSouth(d, NewStringNode("QB64 Buddy")): d = a
  449.     a = LinkEast(a, NewStringNode("Handle"))
  450.     b = LinkEast(a, NewStringNode("FellippeHeitor"))
  451.     a = LinkSouth(a, NewStringNode("Name"))
  452.     b = LinkEast(a, NewStringNode("Fellippe Heitor"))
  453.     a = LinkSouth(a, NewStringNode("Country"))
  454.     b = LinkEast(a, NewStringNode("Brazil"))
  455.     c = LinkEast(b, NewStringNode("Locality"))
  456.     b = LinkEast(c, NewStringNode("My <3"))
  457.     c = LinkEast(b, NewStringNode("JK, it's ___."))
  458.     a = LinkSouth(a, NewStringNode("Birthyear"))
  459.     b = LinkEast(a, NewIntegerNode(1983))
  460.     c = LinkSouth(b, NewStringNode("Sep?"))
  461.     b = LinkSouth(c, NewStringNode("... or was it May?"))
  462.     a = LinkSouth(d, NewStringNode("QB64 Buddy")): d = a
  463.     a = LinkEast(a, NewStringNode("Handle"))
  464.     b = LinkEast(a, NewStringNode("DanTurtle"))
  465.  
  466.     ' Query tests
  467.     'PRINT "Height:"; SquareListHeight(ListId("Tree of Friends"))
  468.     'PRINT "Steve's locality: "; Literal$(StepFirstFromLabel("Tree of Friends", "eesseee"))
  469.     'PRINT "Fellippe's locality: "; Literal$(StepFirstFromLabel("Tree of Friends", "esesseee"))
  470.     'PRINT "Fellippe's birth month: "; Literal$(StepUsing(JumpFrom(StepFirstFromLabel("Tree of Friends", "ese"), "s", 3), "es"))
  471.     'PRINT "Width of Fellippe's Country branch:"; Measure(SeekString("Country", FirstFromLabel("Tree of Friends"), 2), "e")
  472.     'PRINT "Height under Fellippe's Birthyear branch:"; Measure(Nodes(SeekString("Birthyear", FirstFromLabel("Tree of Friends"), 2)).East, "s")
  473.     'PRINT
  474.  
  475.     CALL ReportVisualNodes(FirstFromLabel("Tree of Friends"), 0, .9 * _HEIGHT / 2)
  476.     PRINT: PRINT "Press any key...": SLEEP: CLS
  477.  
  478. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  479.  
  480. SUB DemoArray3D
  481.     DIM TestArray3D(2, 2, 3) AS STRING
  482.     TestArray3D(1, 1, 1) = "one.one.one"
  483.     TestArray3D(1, 1, 2) = "one.one.two"
  484.     TestArray3D(1, 1, 3) = "one.one.three"
  485.     TestArray3D(1, 2, 1) = "one.two.one"
  486.     TestArray3D(1, 2, 2) = "one.two.two"
  487.     TestArray3D(1, 2, 3) = "one.two.three"
  488.     TestArray3D(2, 1, 1) = "two.one.one"
  489.     TestArray3D(2, 1, 2) = "two.one.two"
  490.     TestArray3D(2, 1, 3) = "two.one.three"
  491.     TestArray3D(2, 2, 1) = "two.two.one"
  492.     TestArray3D(2, 2, 2) = "two.two.two"
  493.     TestArray3D(2, 2, 3) = "two.two.three"
  494.     'TestArray3D(3, 1, 1) = "three.one.one"
  495.     'TestArray3D(3, 1, 2) = "three.one.two"
  496.     'TestArray3D(3, 1, 3) = "three.one.three"
  497.     'TestArray3D(3, 2, 1) = "three.two.one"
  498.     'TestArray3D(3, 2, 2) = "three.two.two"
  499.     'TestArray3D(3, 2, 3) = "three.two.three"
  500.     'TestArray3D(4, 1, 1) = "four.one.one"
  501.     'TestArray3D(4, 1, 2) = "four.one.two"
  502.     'TestArray3D(4, 1, 3) = "four.one.three"
  503.     'TestArray3D(4, 2, 1) = "four.two.one"
  504.     'TestArray3D(4, 2, 2) = "four.two.two"
  505.     'TestArray3D(4, 2, 3) = "four.two.three"
  506.     DIM i AS INTEGER
  507.     DIM j AS INTEGER
  508.     DIM k AS INTEGER
  509.     DIM a AS LONG
  510.     DIM b AS LONG
  511.     a = NewLinkedList("Three-Dimensional Array")
  512.     FOR i = 1 TO UBOUND(TestArray3D, 1)
  513.         FOR j = 1 TO UBOUND(TestArray3D, 2)
  514.             FOR k = 1 TO UBOUND(TestArray3D, 3)
  515.                 IF ((i = 1) AND (j = 1) AND (k = 1)) THEN
  516.                     a = LinkEast(a, NewStringNode(TestArray3D(i, j, k)))
  517.                     b = a
  518.                 ELSE
  519.                     IF (k = 1) THEN
  520.                         a = LinkSouth(a, NewStringNode(TestArray3D(i, j, k)))
  521.                         b = a
  522.                     ELSE
  523.                         b = LinkEast(b, NewStringNode(TestArray3D(i, j, k)))
  524.                     END IF
  525.                 END IF
  526.             NEXT
  527.         NEXT
  528.     NEXT
  529.  
  530.     ' Query tests
  531.     PRINT "Height:"; SquareListHeight(ListId("Three-Dimensional Array"))
  532.     PRINT "Width:"; SquareListWidth(ListId("Three-Dimensional Array"))
  533.     PRINT
  534.  
  535.     CALL ReportVisualNodes(FirstFromLabel("Three-Dimensional Array"), 0, .9 * _HEIGHT / 2)
  536.     PRINT: PRINT "Press any key...": SLEEP: CLS
  537.  
  538. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  539. ' Begin BM-component.
  540. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  541.  
  542. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  543. ' Processing
  544. '
  545.  
  546. FUNCTION Evaluate (x AS LONG)
  547.     DIM TheReturn AS LONG
  548.     DIM a AS LONG
  549.     DIM b AS LONG
  550.     a = x
  551.     b = -1
  552.     DO
  553.         a = EvalStep(FirstEmbedded(a))
  554.         IF (a = x) THEN EXIT DO
  555.         IF (a = b) THEN
  556.             a = Nodes(a).South
  557.             IF (a = -1) THEN
  558.                 EXIT DO
  559.             END IF
  560.         ELSE
  561.             b = a
  562.         END IF
  563.     LOOP
  564.     TheReturn = a
  565.     Evaluate = TheReturn
  566.  
  567. FUNCTION EvalStep (x AS LONG)
  568.     DIM TheReturn AS LONG
  569.     DIM SouthernId AS LONG
  570.     DIM NorthernId AS LONG
  571.     DIM FunctionId AS LONG
  572.     DIM i AS LONG
  573.     DIM j AS LONG
  574.     DIM k AS INTEGER
  575.     DIM n AS LONG
  576.     DIM s AS LONG
  577.     DIM RefSpecies AS STRING
  578.     DIM ReturnSpecies AS STRING
  579.     DIM ReturnInteger AS INTEGER
  580.     DIM ReturnString AS STRING
  581.     DIM ReturnDouble AS DOUBLE
  582.     DIM MultiPass AS INTEGER
  583.  
  584.     RefSpecies = ""
  585.     FunctionId = x
  586.     ReturnSpecies = ""
  587.     ReturnInteger = 0
  588.     ReturnString = ""
  589.     ReturnDouble = 0
  590.  
  591.     ' Pre-evaluation
  592.     IF (x <> -1) THEN
  593.         SouthernId = x
  594.         i = x
  595.         DO
  596.             n = Nodes(i).North
  597.             IF (n <> -1) THEN
  598.                 i = n
  599.             ELSE
  600.                 NorthernId = i
  601.                 EXIT DO
  602.             END IF
  603.         LOOP
  604.         FunctionId = Nodes(NorthernId).West
  605.         ReturnSpecies = Nodes(FunctionId).Species
  606.         SELECT CASE ReturnSpecies
  607.             CASE "integer"
  608.                 ReturnInteger = IntegerData(Nodes(FunctionId).Reference)
  609.             CASE "string"
  610.                 ReturnString = StringData(Nodes(FunctionId).Reference)
  611.             CASE "double"
  612.                 ReturnDouble = DoubleData(Nodes(FunctionId).Reference)
  613.         END SELECT
  614.     END IF
  615.  
  616.     ' Lambda substitution
  617.     i = NorthernId
  618.     DIM lf AS INTEGER
  619.     lf = 0
  620.     DO
  621.         IF (Nodes(i).Species = "string") THEN
  622.             IF (StringData(Nodes(i).Reference) = "[1]") THEN
  623.                 j = LambdaMatrix(LambdaIndex, 1)
  624.                 Nodes(i).Species = Nodes(j).Species
  625.                 Nodes(i).Reference = Nodes(j).Reference
  626.                 lf = 1
  627.             END IF
  628.             IF (StringData(Nodes(i).Reference) = "[2]") THEN
  629.                 j = LambdaMatrix(LambdaIndex, 2)
  630.                 Nodes(i).Species = Nodes(j).Species
  631.                 Nodes(i).Reference = Nodes(j).Reference
  632.                 lf = 1
  633.             END IF
  634.         END IF
  635.         IF (i = SouthernId) THEN
  636.             EXIT DO
  637.         ELSE
  638.             s = Nodes(i).South
  639.             i = s
  640.         END IF
  641.     LOOP
  642.     IF (lf = 1) THEN
  643.         FOR k = 1 TO LambdaArgCount(LambdaIndex)
  644.             j = Unlink(LambdaMatrix(LambdaIndex, k))
  645.         NEXT
  646.         LambdaArgCount(LambdaIndex) = 0
  647.         LambdaIndex = LambdaIndex - 1
  648.     END IF
  649.  
  650.     ' Determine return species
  651.     i = NorthernId
  652.     DO
  653.         IF (i = -1) THEN EXIT DO
  654.         IF (Nodes(i).Species = "string") THEN RefSpecies = "string"
  655.         IF ((Nodes(i).Species = "double") AND (RefSpecies <> "string")) THEN RefSpecies = "double"
  656.         IF ((Nodes(i).Species = "integer") AND (RefSpecies <> "string") AND (RefSpecies <> "double")) THEN RefSpecies = "integer"
  657.         i = Nodes(i).South
  658.     LOOP
  659.  
  660.     ' Single-pass evaluation
  661.     MultiPass = 0
  662.     SELECT CASE Literal$(FunctionId)
  663.         CASE "*"
  664.             MultiPass = 1
  665.             ReturnSpecies = RefSpecies
  666.             ReturnInteger = 1
  667.             ReturnDouble = 1
  668.         CASE "+"
  669.             MultiPass = 1
  670.             ReturnSpecies = RefSpecies
  671.             ReturnInteger = 0
  672.             ReturnDouble = 0
  673.         CASE "/"
  674.             MultiPass = 0
  675.             SELECT CASE Nodes(NorthernId).Species
  676.                 CASE "integer"
  677.                     ReturnSpecies = "double"
  678.                     SELECT CASE Nodes(SouthernId).Species
  679.                         CASE "integer"
  680.                             ReturnDouble = IntegerData(Nodes(NorthernId).Reference) / IntegerData(Nodes(SouthernId).Reference)
  681.                         CASE "double"
  682.                             ReturnDouble = IntegerData(Nodes(NorthernId).Reference) / DoubleData(Nodes(SouthernId).Reference)
  683.                     END SELECT
  684.                 CASE "string"
  685.                     ReturnSpecies = "string"
  686.                     ReturnString = Literal$(NorthernId) + "/" + Literal$(SouthernId)
  687.                 CASE "double"
  688.                     ReturnSpecies = "double"
  689.                     SELECT CASE Nodes(SouthernId).Species
  690.                         CASE "integer"
  691.                             ReturnDouble = DoubleData(Nodes(NorthernId).Reference) / IntegerData(Nodes(SouthernId).Reference)
  692.                         CASE "double"
  693.                             ReturnDouble = DoubleData(Nodes(NorthernId).Reference) / DoubleData(Nodes(SouthernId).Reference)
  694.                     END SELECT
  695.             END SELECT
  696.             i = Unlink(NorthernId)
  697.             i = Unlink(SouthernId)
  698.         CASE "cos"
  699.             IF (NorthernId = SouthernId) THEN
  700.                 MultiPass = 0
  701.                 i = NorthernId
  702.                 SELECT CASE Nodes(i).Species
  703.                     CASE "integer"
  704.                         ReturnSpecies = "double"
  705.                         ReturnDouble = COS(IntegerData(Nodes(i).Reference))
  706.                     CASE "string"
  707.                         ReturnSpecies = "string"
  708.                         ReturnString = "cos" + "(" + Literal$(i) + ")"
  709.                     CASE "double"
  710.                         ReturnSpecies = "double"
  711.                         ReturnDouble = COS(DoubleData(Nodes(i).Reference))
  712.                 END SELECT
  713.                 i = Unlink(i)
  714.             ELSE
  715.                 MultiPass = 1
  716.                 ReturnSpecies = "string"
  717.                 ReturnString = "(" + "cos" + ")"
  718.             END IF
  719.         CASE "lambda"
  720.             MultiPass = 1
  721.             LambdaIndex = LambdaIndex + 1
  722.             ReturnSpecies = "string"
  723.             ReturnString = "(" + "lambda" + ")"
  724.         CASE "(" + "lambda" + ")"
  725.             '
  726.     END SELECT
  727.  
  728.     ' Multi-pass evaluation
  729.     IF (MultiPass = 1) THEN
  730.         i = NorthernId
  731.         DO
  732.             SELECT CASE Literal$(FunctionId)
  733.                 CASE "*"
  734.                     SELECT CASE ReturnSpecies
  735.                         CASE "integer"
  736.                             SELECT CASE Nodes(i).Species
  737.                                 CASE "integer"
  738.                                     ReturnInteger = ReturnInteger * IntegerData(Nodes(i).Reference)
  739.                                 CASE "double"
  740.                                     ReturnInteger = ReturnInteger * DoubleData(Nodes(i).Reference)
  741.                             END SELECT
  742.                         CASE "string"
  743.                             ReturnString = ReturnString + Literal$(i)
  744.                         CASE "double"
  745.                             SELECT CASE Nodes(i).Species
  746.                                 CASE "integer"
  747.                                     ReturnDouble = ReturnDouble * IntegerData(Nodes(i).Reference)
  748.                                 CASE "double"
  749.                                     ReturnDouble = ReturnDouble * DoubleData(Nodes(i).Reference)
  750.                             END SELECT
  751.                     END SELECT
  752.                     IF (i = SouthernId) THEN
  753.                         i = Unlink(i)
  754.                         EXIT DO
  755.                     ELSE
  756.                         s = Nodes(i).South
  757.                         i = Unlink(i)
  758.                         i = s
  759.                     END IF
  760.                 CASE "+"
  761.                     SELECT CASE ReturnSpecies
  762.                         CASE "integer"
  763.                             SELECT CASE Nodes(i).Species
  764.                                 CASE "integer"
  765.                                     ReturnInteger = ReturnInteger + IntegerData(Nodes(i).Reference)
  766.                                 CASE "double"
  767.                                     ReturnInteger = ReturnInteger + DoubleData(Nodes(i).Reference)
  768.                             END SELECT
  769.                         CASE "string"
  770.                             ReturnString = ReturnString + Literal$(i)
  771.                         CASE "double"
  772.                             SELECT CASE Nodes(i).Species
  773.                                 CASE "integer"
  774.                                     ReturnDouble = ReturnDouble + IntegerData(Nodes(i).Reference)
  775.                                 CASE "double"
  776.                                     ReturnDouble = ReturnDouble + DoubleData(Nodes(i).Reference)
  777.                             END SELECT
  778.                     END SELECT
  779.                     IF (i = SouthernId) THEN
  780.                         i = Unlink(i)
  781.                         EXIT DO
  782.                     ELSE
  783.                         s = Nodes(i).South
  784.                         i = Unlink(i)
  785.                         i = s
  786.                     END IF
  787.                 CASE "cos"
  788.                     SELECT CASE Nodes(i).Species
  789.                         CASE "integer"
  790.                             Nodes(i).Species = "double"
  791.                             Nodes(i).Reference = NewDoubleData(COS(IntegerData(Nodes(i).Reference)))
  792.                         CASE "string"
  793.                             Nodes(i).Reference = NewStringData("cos" + "(" + Literal$(i) + ")")
  794.                         CASE "double"
  795.                             Nodes(i).Species = "double"
  796.                             Nodes(i).Reference = NewDoubleData(COS(DoubleData(Nodes(i).Reference)))
  797.                     END SELECT
  798.                     IF (i = SouthernId) THEN
  799.                         EXIT DO
  800.                     ELSE
  801.                         s = Nodes(i).South
  802.                         i = s
  803.                     END IF
  804.                 CASE "lambda"
  805.                     LambdaArgCount(LambdaIndex) = LambdaArgCount(LambdaIndex) + 1
  806.                     LambdaMatrix(LambdaIndex, LambdaArgCount(LambdaIndex)) = i
  807.                     IF (i = SouthernId) THEN
  808.                         EXIT DO
  809.                     ELSE
  810.                         s = Nodes(i).South
  811.                         i = s
  812.                     END IF
  813.             END SELECT
  814.         LOOP
  815.     END IF
  816.  
  817.     SELECT CASE ReturnSpecies
  818.         CASE "integer"
  819.             Nodes(FunctionId).Species = ReturnSpecies
  820.             Nodes(FunctionId).Reference = NewIntegerData(ReturnInteger)
  821.         CASE "string"
  822.             Nodes(FunctionId).Species = ReturnSpecies
  823.             Nodes(FunctionId).Reference = NewStringData(ReturnString)
  824.         CASE "double"
  825.             Nodes(FunctionId).Species = ReturnSpecies
  826.             Nodes(FunctionId).Reference = NewDoubleData(ReturnDouble)
  827.     END SELECT
  828.  
  829.     TheReturn = FunctionId
  830.     EvalStep = TheReturn
  831.  
  832. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  833. ' Seek and recall
  834. '
  835.  
  836. FUNCTION FirstEmbedded (x AS LONG)
  837.     DIM TheReturn AS LONG
  838.     TheReturn = MostEmbeddedRecur(x, -1)
  839.     FirstEmbedded = TheReturn
  840.  
  841. FUNCTION MostEmbeddedRecur (x AS LONG, y AS LONG)
  842.     DIM TheReturn AS LONG
  843.     DIM s AS LONG
  844.     DIM e AS LONG
  845.     s = Nodes(x).South
  846.     e = Nodes(x).East
  847.     IF (e <> -1) THEN
  848.         TheReturn = MostEmbeddedRecur(e, y)
  849.     END IF
  850.     IF (s <> -1) THEN
  851.         TheReturn = MostEmbeddedRecur(s, y)
  852.     END IF
  853.     IF (e = -1) AND (s = -1) AND (y = -1) THEN
  854.         y = x
  855.     END IF
  856.     MostEmbeddedRecur = y
  857.  
  858. FUNCTION SeekString (t AS STRING, x AS LONG, r AS INTEGER)
  859.     DIM TheReturn AS LONG
  860.     DIM s AS LONG
  861.     DIM e AS LONG
  862.     TheReturn = -1
  863.     s = Nodes(x).South
  864.     e = Nodes(x).East
  865.     IF (StringData(Nodes(x).Reference) = t) THEN
  866.         TheReturn = x
  867.         r = r - 1
  868.     ELSE
  869.         IF (e <> -1) AND (r > 0) THEN
  870.             TheReturn = SeekString(t, e, r)
  871.         END IF
  872.         IF (s <> -1) AND (r > 0) THEN
  873.             TheReturn = SeekString(t, s, r)
  874.         END IF
  875.     END IF
  876.     SeekString = TheReturn
  877.  
  878. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  879. ' Navigation
  880. '
  881.  
  882. FUNCTION ListId (t AS STRING)
  883.     ' Takes linked list label as argument.
  884.     ' Returns index of linked list.
  885.     DIM TheReturn AS LONG
  886.     DIM k AS LONG
  887.     TheReturn = -1
  888.     FOR k = 1 TO UBOUND(LinkedList)
  889.         IF (LinkedList(k).Label = t) THEN
  890.             TheReturn = k
  891.             EXIT FOR
  892.         END IF
  893.     NEXT
  894.     ListId = TheReturn
  895.  
  896. FUNCTION FirstFromLabel (t AS STRING)
  897.     ' Takes linked list label as argument.
  898.     ' Returns first node identity.
  899.     DIM TheReturn AS LONG
  900.     TheReturn = LinkedList(ListId(t)).FirstNode
  901.     FirstFromLabel = TheReturn
  902.  
  903. FUNCTION StepFirstFromLabel (x AS STRING, t AS STRING)
  904.     DIM TheReturn AS LONG
  905.     TheReturn = StepUsing(FirstFromLabel(x), t)
  906.     StepFirstFromLabel = TheReturn
  907.  
  908. FUNCTION JumpFrom (x AS LONG, t AS STRING, r AS INTEGER)
  909.     DIM TheReturn AS LONG
  910.     TheReturn = x
  911.     IF (r > 0) THEN
  912.         SELECT CASE t
  913.             CASE "n"
  914.                 TheReturn = JumpFrom(Nodes(x).North, "n", r - 1)
  915.             CASE "s"
  916.                 TheReturn = JumpFrom(Nodes(x).South, "s", r - 1)
  917.             CASE "e"
  918.                 TheReturn = JumpFrom(Nodes(x).East, "e", r - 1)
  919.             CASE "w"
  920.                 TheReturn = JumpFrom(Nodes(x).West, "w", r - 1)
  921.         END SELECT
  922.     END IF
  923.     JumpFrom = TheReturn
  924.  
  925. FUNCTION StepUsing (x AS LONG, t AS STRING)
  926.     DIM TheReturn AS LONG
  927.     DIM i AS LONG
  928.     DIM j AS LONG
  929.     DIM k AS INTEGER
  930.     i = x
  931.     FOR k = 1 TO LEN(t)
  932.         SELECT CASE MID$(t, k, 1)
  933.             CASE "n"
  934.                 j = Nodes(i).North
  935.                 IF (j <> -1) THEN i = j
  936.             CASE "s"
  937.                 j = Nodes(i).South
  938.                 IF (j <> -1) THEN i = j
  939.             CASE "e"
  940.                 j = Nodes(i).East
  941.                 IF (j <> -1) THEN i = j
  942.             CASE "w"
  943.                 j = Nodes(i).West
  944.                 IF (j <> -1) THEN i = j
  945.         END SELECT
  946.     NEXT
  947.     TheReturn = i
  948.     StepUsing = TheReturn
  949.  
  950. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  951. ' Internal metrics
  952. '
  953.  
  954. FUNCTION SquareListHeight (x AS INTEGER)
  955.     DIM TheReturn AS INTEGER
  956.     TheReturn = Measure(Nodes(LinkedList(x).FirstNode).East, "s")
  957.     SquareListHeight = TheReturn
  958.  
  959. FUNCTION SquareListWidth (x AS INTEGER)
  960.     DIM TheReturn AS INTEGER
  961.     TheReturn = Measure(Nodes(LinkedList(x).FirstNode).East, "e")
  962.     SquareListWidth = TheReturn
  963.  
  964. FUNCTION Measure (x AS LONG, t AS STRING)
  965.     DIM TheReturn AS INTEGER
  966.     TheReturn = CountSteps(x, -1, t)
  967.     Measure = TheReturn
  968.  
  969. FUNCTION CountSteps (x AS LONG, y AS LONG, t AS STRING)
  970.     DIM TheReturn AS INTEGER
  971.     DIM k AS LONG
  972.     TheReturn = 0
  973.     SELECT CASE t
  974.         CASE "n"
  975.             k = Nodes(x).North
  976.         CASE "s"
  977.             k = Nodes(x).South
  978.         CASE "e"
  979.             k = Nodes(x).East
  980.         CASE "w"
  981.             k = Nodes(x).West
  982.     END SELECT
  983.     IF (k = y) THEN
  984.         TheReturn = TheReturn + 1
  985.     ELSE
  986.         IF (k <> -1) THEN
  987.             TheReturn = TheReturn + 1 + CountSteps(k, y, t)
  988.         END IF
  989.     END IF
  990.     CountSteps = TheReturn
  991.  
  992. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  993. ' Printing and ReportVisualNodesing
  994. '
  995.  
  996. FUNCTION PrintLinkedList$ (x AS STRING)
  997.     DIM TheReturn AS STRING
  998.     DIM t AS STRING
  999.     t = ListNodesRecur$(0, LinkedList(ListId(x)).FirstNode)
  1000.     TheReturn = LEFT$(t, LEN(t) - 1)
  1001.     PrintLinkedList$ = TheReturn
  1002.  
  1003. FUNCTION ListNodesRecur$ (i AS INTEGER, x AS LONG)
  1004.     DIM TheReturn AS STRING
  1005.     DIM s AS LONG
  1006.     DIM e AS LONG
  1007.     s = Nodes(x).South
  1008.     e = Nodes(x).East
  1009.     TheReturn = TheReturn + SPACE$(i) + Literal$(x) + CHR$(10)
  1010.     IF (e <> -1) THEN
  1011.         TheReturn = TheReturn + ListNodesRecur$(i + 2, e)
  1012.     END IF
  1013.     IF (s <> -1) THEN
  1014.         TheReturn = TheReturn + ListNodesRecur$(i, s)
  1015.     END IF
  1016.     ListNodesRecur$ = TheReturn
  1017.  
  1018. FUNCTION Literal$ (x AS LONG)
  1019.     DIM TheReturn AS STRING
  1020.     TheReturn = ""
  1021.     IF (x <> -1) THEN
  1022.         SELECT CASE Nodes(x).Species
  1023.             CASE "integer"
  1024.                 TheReturn = LTRIM$(RTRIM$(STR$(IntegerData(Nodes(x).Reference))))
  1025.             CASE "string"
  1026.                 TheReturn = StringData(Nodes(x).Reference)
  1027.             CASE "double"
  1028.                 TheReturn = LTRIM$(RTRIM$(STR$(DoubleData(Nodes(x).Reference))))
  1029.         END SELECT
  1030.     END IF
  1031.     Literal$ = TheReturn
  1032.  
  1033. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1034. ' Linked list construction
  1035. '
  1036.  
  1037. FUNCTION NewUnitList (t AS STRING, x AS LONG)
  1038.     DIM TheReturn AS LONG
  1039.     DIM k AS LONG
  1040.     TheReturn = NewLinkedList(t)
  1041.     k = LinkEast(TheReturn, x)
  1042.     NewUnitList = TheReturn
  1043.  
  1044. FUNCTION NewLinkedList (t AS STRING)
  1045.     DIM i AS LONG
  1046.     DIM k AS LONG
  1047.     k = NewStringNode(t)
  1048.     i = NextOpenLinkedList(1)
  1049.     LinkedListRegister(i) = i
  1050.     LinkedList(i).Label = StringData(Nodes(k).Reference)
  1051.     LinkedList(i).FirstNode = k
  1052.     NewLinkedList = k
  1053.  
  1054. FUNCTION NextOpenLinkedList (x AS LONG)
  1055.     DIM TheReturn AS LONG
  1056.     DIM k AS LONG
  1057.     TheReturn = -1
  1058.     FOR k = x TO UBOUND(LinkedListRegister)
  1059.         IF (LinkedListRegister(k) = 0) THEN
  1060.             TheReturn = k
  1061.             EXIT FOR
  1062.         END IF
  1063.     NEXT
  1064.     NextOpenLinkedList = TheReturn
  1065.  
  1066. FUNCTION LinkSouth (n AS LONG, s AS LONG)
  1067.     DIM TheReturn AS LONG
  1068.     Nodes(s).North = n
  1069.     Nodes(n).South = s
  1070.     TheReturn = s
  1071.     LinkSouth = TheReturn
  1072.  
  1073. FUNCTION LinkEast (w AS LONG, e AS LONG)
  1074.     DIM TheReturn AS LONG
  1075.     Nodes(w).East = e
  1076.     Nodes(e).West = w
  1077.     TheReturn = e
  1078.     LinkEast = TheReturn
  1079.  
  1080. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1081. ' Linked list editing
  1082. '
  1083. FUNCTION InsertSouth (n AS LONG, x AS LONG)
  1084.     DIM s AS LONG
  1085.     s = Nodes(n).South
  1086.     Nodes(n).South = x
  1087.     Nodes(x).North = n
  1088.     Nodes(x).South = s
  1089.     IF (s <> -1) THEN
  1090.         Nodes(s).North = x
  1091.     END IF
  1092.     InsertSouth = x
  1093.  
  1094. FUNCTION InsertEast (w AS LONG, x AS LONG)
  1095.     DIM e AS LONG
  1096.     e = Nodes(w).East
  1097.     Nodes(w).East = x
  1098.     Nodes(x).West = w
  1099.     Nodes(x).East = e
  1100.     IF (e <> -1) THEN
  1101.         Nodes(e).West = x
  1102.     END IF
  1103.     InsertEast = x
  1104.  
  1105. FUNCTION Unlink (x AS LONG)
  1106.     DIM n AS LONG
  1107.     DIM s AS LONG
  1108.     DIM e AS LONG
  1109.     DIM w AS LONG
  1110.     n = Nodes(x).North
  1111.     s = Nodes(x).South
  1112.     e = Nodes(x).East
  1113.     w = Nodes(x).West
  1114.     IF (n <> -1) THEN Nodes(n).South = s
  1115.     IF (s <> -1) THEN Nodes(s).North = n
  1116.     IF (e <> -1) THEN Nodes(e).West = w
  1117.     IF (w <> -1) THEN Nodes(w).East = e
  1118.     IdentityRegister(x) = 0
  1119.     Unlink = x
  1120.  
  1121. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1122. ' Node creation
  1123. '
  1124.  
  1125. FUNCTION NextOpenIdentity (x AS LONG)
  1126.     DIM TheReturn AS LONG
  1127.     DIM k AS LONG
  1128.     TheReturn = -1
  1129.     FOR k = x TO UBOUND(IdentityRegister)
  1130.         IF (IdentityRegister(k) = 0) THEN
  1131.             TheReturn = k
  1132.             EXIT FOR
  1133.         END IF
  1134.     NEXT
  1135.     NextOpenIdentity = TheReturn
  1136.  
  1137. FUNCTION NewNode (x AS LONG, t AS STRING, r AS LONG)
  1138.     DIM i AS LONG
  1139.     i = NextOpenIdentity(x)
  1140.     IdentityRegister(i) = i
  1141.     Nodes(i).Identity = i
  1142.     Nodes(i).Species = t
  1143.     Nodes(i).Reference = r
  1144.     Nodes(i).North = -1
  1145.     Nodes(i).South = -1
  1146.     Nodes(i).East = -1
  1147.     Nodes(i).West = -1
  1148.     NewNode = i
  1149.  
  1150. FUNCTION NewIntegerNode (x AS INTEGER)
  1151.     NewIntegerNode = NewNode(1, "integer", NewIntegerData(x))
  1152.  
  1153. FUNCTION NewStringNode (x AS STRING)
  1154.     NewStringNode = NewNode(1, "string", NewStringData(x))
  1155.  
  1156. FUNCTION NewDoubleNode (x AS DOUBLE)
  1157.     NewDoubleNode = NewNode(1, "double", NewDoubleData(x))
  1158.  
  1159. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1160. ' Node editing
  1161. '
  1162.  
  1163. FUNCTION EditIntegerReference (i AS LONG, x AS INTEGER)
  1164.     DIM z AS LONG
  1165.     z = NewIntegerData(x)
  1166.     Nodes(i).Reference = z
  1167.     EditIntegerReference = z
  1168.  
  1169. FUNCTION EditStringReference (i AS LONG, x AS STRING)
  1170.     DIM z AS LONG
  1171.     z = NewStringData(x)
  1172.     Nodes(i).Reference = z
  1173.     EditStringReference = z
  1174.  
  1175. FUNCTION EditDoubleReference (i AS LONG, x AS DOUBLE)
  1176.     DIM z AS LONG
  1177.     z = NewDoubleData(x)
  1178.     Nodes(i).Reference = z
  1179.     EditDoubleReference = z
  1180.  
  1181. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1182. ' Data assimilation
  1183. '
  1184.  
  1185. FUNCTION NewIntegerData (x AS INTEGER)
  1186.     DIM TheReturn AS LONG
  1187.     DIM k AS LONG
  1188.     TheReturn = -1
  1189.     FOR k = 1 TO UBOUND(IntegerData)
  1190.         IF (IntegerData(k) = x) THEN
  1191.             TheReturn = k
  1192.             EXIT FOR
  1193.         END IF
  1194.     NEXT
  1195.     IF (TheReturn = -1) THEN
  1196.         REDIM _PRESERVE IntegerData(UBOUND(IntegerData) + 1)
  1197.         IntegerData(UBOUND(IntegerData)) = x
  1198.         TheReturn = UBOUND(IntegerData)
  1199.     END IF
  1200.     NewIntegerData = TheReturn
  1201.  
  1202. FUNCTION NewStringData (x AS STRING)
  1203.     DIM TheReturn AS LONG
  1204.     DIM k AS LONG
  1205.     TheReturn = -1
  1206.     FOR k = 1 TO UBOUND(StringData)
  1207.         IF (StringData(k) = x) THEN
  1208.             TheReturn = k
  1209.             EXIT FOR
  1210.         END IF
  1211.     NEXT
  1212.     IF (TheReturn = -1) THEN
  1213.         REDIM _PRESERVE StringData(UBOUND(StringData) + 1)
  1214.         StringData(UBOUND(Stringdata)) = x
  1215.         TheReturn = UBOUND(StringData)
  1216.     END IF
  1217.     NewStringData = TheReturn
  1218.  
  1219. FUNCTION NewDoubleData (x AS DOUBLE)
  1220.     DIM TheReturn AS LONG
  1221.     DIM k AS LONG
  1222.     TheReturn = -1
  1223.     FOR k = 1 TO UBOUND(DoubleData)
  1224.         IF (DoubleData(k) = x) THEN
  1225.             TheReturn = k
  1226.             EXIT FOR
  1227.         END IF
  1228.     NEXT
  1229.     IF (TheReturn = -1) THEN
  1230.         REDIM _PRESERVE DoubleData(UBOUND(DoubleData) + 1)
  1231.         DoubleData(UBOUND(DoubleData)) = x
  1232.         TheReturn = UBOUND(DoubleData)
  1233.     END IF
  1234.     NewDoubleData = TheReturn
  1235.  
  1236. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1237. ' End BM-component.
  1238. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1239.  
  1240. '''
  1241. 'FOR k = 1 TO UBOUND(LinkedListRegister)
  1242. '    IF (LinkedListRegister(k) <> 0) THEN
  1243. '        PRINT LinkedList(k).Label
  1244. '    END IF
  1245. 'NEXT
  1246. 'FOR k = 1 TO UBOUND(IdentityRegister)
  1247. '    IF (IdentityRegister(k) <> 0) THEN
  1248. '        a = IdentityRegister(k)
  1249. '        PRINT Literal$(a) + " (" + Literal$(Nodes(a).North) + "," + Literal$(Nodes(a).South) + "," + Literal$(Nodes(a).East) + "," + Literal$(Nodes(a).West) + ")" '+ CHR$(10)
  1250. '    END IF
  1251. 'NEXT
  1252. 'FOR k = 1 TO UBOUND(IdentityRegister)
  1253. '    IF (IdentityRegister(k) <> 0) THEN
  1254. '        CALL DefineVisualNode(k)
  1255. '    END IF
  1256. 'NEXT
  1257. '''
ss.png
* ss.png (Filesize: 4.25 KB, Dimensions: 528x291, Views: 180)
You're not done when it works, you're done when it's right.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: A new take on arrays and data
« Reply #22 on: April 19, 2020, 12:36:17 pm »
Wow, graphics plus linked lists. Does this mean I get to call you Art Linklister?

Sorry, it turns out us old farts say the darnedest things, too. Especially us really old ones, like flukiluke. I never new he was born during the Middle Ages until I ran your demo... and in May, nonetheless. I took offense at first, but then recovered when I realized all your QB buds were born in May. Me? I was born in protest.

Nice work, and glad you're still at work. I think if everyone did virus control practices like we .orggers do, we'd have no virus transmission at all. For instance, Steve and I practice staying 3,000 miles apart at all times. Well, at least until I go out to get my mail, then it's only 2,999.95 miles.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #23 on: April 30, 2020, 10:10:58 pm »
Hello all,

Made many updates to this codebase - plenty of boring eggheaded stuff I'll skip - because this update has mouse control. Yup, GUI stuff, who'd have thought it? What you can do is click+drag to move nodes around, with a hitch. If you move a node that has child nodes, they also move. It's easier done than said:

Code: QB64: [Select]
  1. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2. ' Meta:
  3. '
  4.  
  5.  
  6. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  7. ' Begin BI-component.
  8. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  9.  
  10. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  11. ' Hard arrays to store actual data:
  12. '
  13. REDIM SHARED IntegerData(0) AS INTEGER
  14. REDIM SHARED StringData(0) AS STRING
  15. REDIM SHARED DoubleData(0) AS DOUBLE
  16.  
  17. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  18. ' Temp variable(s):
  19. '
  20.  
  21.  
  22. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  23. ' Nodes:
  24. '
  25.  
  26. ' Node structure
  27. TYPE Node
  28.     Identity AS LONG '   Address in identity register
  29.     Species AS STRING '  Data type
  30.     Reference AS LONG '  Pointer to hard array index
  31.     North AS LONG '
  32.     South AS LONG '
  33.     East AS LONG '
  34.     West AS LONG '       (Orientation)
  35.  
  36. DIM MaxNodes AS INTEGER
  37. MaxNodes = 9999
  38.  
  39. ' Node visibility toggle
  40. DIM SHARED IdentityRegister(MaxNodes) AS LONG
  41. FOR k = 1 TO UBOUND(IdentityRegister)
  42.     IdentityRegister(k) = 0
  43.  
  44. ' Node storage
  45. DIM SHARED Nodes(MaxNodes) AS Node
  46.  
  47. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  48. ' Linked lists:
  49. '
  50.  
  51. ' Linked list structure
  52. TYPE LinkedListStructure
  53.     Label AS STRING
  54.     HeadNode AS LONG
  55.  
  56. DIM MaxLinkedLists AS INTEGER
  57. MaxLinkedLists = 99
  58.  
  59. ' Linked list visibility toggle
  60. DIM SHARED LinkedListRegister(MaxLinkedLists) AS INTEGER
  61. FOR k = 1 TO UBOUND(LinkedListRegister)
  62.     LinkedListRegister(k) = 0
  63.  
  64. ' Linked list storage
  65. DIM SHARED LinkedList(MaxLinkedLists) AS LinkedListStructure
  66.  
  67. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  68. ' Processing
  69. '
  70. DIM SHARED LambdaMatrix(99, 9) AS LONG
  71. DIM SHARED LambdaIndex AS INTEGER
  72. DIM SHARED LambdaArgCount(9) AS LONG
  73. LambdaIndex = 0
  74.  
  75. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  76. ' End BI-component.
  77. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  78.  
  79. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  80. ' Pre-Main
  81. '
  82.  
  83. SCREEN _NEWIMAGE(800, 600, 32)
  84.  
  85. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  86. ' Visual Nodes (OPTIONAL)
  87. '
  88.  
  89. TYPE Vector
  90.     x AS DOUBLE
  91.     y AS DOUBLE
  92.  
  93. ' Visual node structure
  94. TYPE VisualNodesStructure
  95.     Reference AS LONG '    Points to a node.
  96.     BoxCenter AS Vector
  97.     BoxHeight AS DOUBLE
  98.     BoxWidth AS DOUBLE
  99.     CornerNE AS Vector
  100.     CornerNW AS Vector
  101.     CornerSE AS Vector
  102.     CornerSW AS Vector
  103.     AntennaN AS Vector
  104.     AntennaS AS Vector
  105.     AntennaE AS Vector
  106.     AntennaW AS Vector
  107.  
  108. DIM MaxVisualNodess AS INTEGER
  109. DIM SHARED VisualNodesCount AS INTEGER
  110. MaxVisualNodess = 256
  111. VisualNodesCount = 0
  112.  
  113. ' Visual node storage
  114. DIM SHARED VisualNodes(MaxVisualNodess) AS VisualNodesStructure
  115.  
  116. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  117. ' Main
  118. '
  119.  
  120.  
  121. ''
  122. 'CALL LoadArray3D("Three-Diensional Array")
  123. ''
  124. CALL DemoTree
  125. CALL UserLoop
  126. ''
  127. 'CALL DemoTreeEdit
  128. ''
  129. 'CALL DemoArithmetic
  130. ''
  131. 'CALL DemoList
  132. ''
  133. ''CALL DemoLambda
  134. ''
  135. 'CALL DemoMerge
  136.  
  137.  
  138.  
  139. a = NewUnitList("cow", NewIntegerNode(7))
  140. a = NewUnitList("goo", NewDoubleNode(5.6))
  141.  
  142. VisualNodesCount = 0
  143. FOR k = 1 TO UBOUND(LinkedListRegister)
  144.     IF (LinkedListRegister(k) <> 0) THEN
  145.         'PRINT PrintLinkedList$(LinkedList(k).HeadNode)
  146.         CALL BuildVisualList(LinkedList(k).HeadNode, -1, .9 * (RND - .5) * _WIDTH, .9 * _HEIGHT / 2)
  147.     END IF
  148.  
  149. CALL UserLoop
  150.  
  151.  
  152.  
  153. SUB Halt
  154.     PRINT "Press any key..."
  155.     _DISPLAY
  156.     DO: LOOP UNTIL INKEY$ <> ""
  157.     CLS
  158.     _DISPLAY
  159.  
  160. SUB UserLoop
  161.     DIM xx AS DOUBLE
  162.     DIM yy AS DOUBLE
  163.     DIM dx AS DOUBLE
  164.     DIM dy AS DOUBLE
  165.     DIM r AS DOUBLE
  166.     DIM d AS DOUBLE
  167.     DIM k AS INTEGER
  168.     DIM i AS INTEGER
  169.  
  170.     _KEYCLEAR
  171.  
  172.     DO
  173.         DO WHILE _MOUSEINPUT
  174.             r = 9999
  175.             i = -1
  176.             xx = _MOUSEX
  177.             yy = _MOUSEY
  178.             IF ((xx > 0) AND (xx < _WIDTH) AND (yy > 0) AND (yy < _HEIGHT)) THEN
  179.                 xx = (xx - _WIDTH / 2)
  180.                 yy = (-yy + _HEIGHT / 2)
  181.                 FOR k = 1 TO VisualNodesCount
  182.                     d = (xx - VisualNodes(k).BoxCenter.x) * (xx - VisualNodes(k).BoxCenter.x) + (yy - VisualNodes(k).BoxCenter.y) * (yy - VisualNodes(k).BoxCenter.y)
  183.                     IF (d < r) THEN
  184.                         r = d
  185.                         i = k
  186.                         dx = xx - VisualNodes(k).BoxCenter.x
  187.                         dy = yy - VisualNodes(k).BoxCenter.y
  188.                     END IF
  189.                 NEXT
  190.             END IF
  191.             IF (i <> -1) THEN
  192.                 IF _MOUSEBUTTON(1) THEN
  193.                     CALL MoveVisualNodesRecur(i, VisualNodes(i).Reference, dx, dy)
  194.                 END IF
  195.             END IF
  196.         LOOP
  197.  
  198.         k = _KEYHIT
  199.         SELECT CASE k
  200.             CASE 27
  201.                 _KEYCLEAR
  202.                 EXIT SUB
  203.         END SELECT
  204.  
  205.         CLS
  206.  
  207.         CALL DrawAllNodes
  208.  
  209.         IF (i <> -1) THEN
  210.             IF (xx > VisualNodes(i).BoxCenter.x - VisualNodes(i).BoxWidth / 2) AND (xx < VisualNodes(i).BoxCenter.x + VisualNodes(i).BoxWidth / 2) THEN
  211.                 IF (yy > VisualNodes(i).BoxCenter.y - VisualNodes(i).BoxHeight / 2) AND (yy < VisualNodes(i).BoxCenter.y + VisualNodes(i).BoxHeight / 2) THEN
  212.                     LOCATE 1, 1: PRINT Literal$(VisualNodes(i).Reference)
  213.                 END IF
  214.             END IF
  215.         END IF
  216.  
  217.         _DISPLAY
  218.         _LIMIT 30
  219.     LOOP
  220.  
  221.  
  222. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  223. ' Visual Node graphics (OPTIONAL)
  224. '
  225.  
  226. SUB BuildVisualList (x AS LONG, i AS INTEGER, x0 AS DOUBLE, y0 AS DOUBLE)
  227.     IF (i <> -1) THEN
  228.         VisualNodesCount = i
  229.     END IF
  230.     CALL VisualListRecur(x, x0, y0)
  231.  
  232. SUB DrawAllNodes
  233.     DIM k AS INTEGER
  234.     FOR k = 1 TO VisualNodesCount
  235.         CALL DrawWires(k)
  236.         CALL DrawSingleNode(k)
  237.     NEXT
  238.  
  239. SUB VisualListRecur (x AS LONG, x0 AS DOUBLE, y0 AS DOUBLE)
  240.     DIM s AS LONG
  241.     DIM e AS LONG
  242.     DIM dxtmp AS DOUBLE
  243.     s = Nodes(x).South
  244.     e = Nodes(x).East
  245.     VisualNodesCount = VisualNodesCount + 1
  246.     CALL DefineVisualNode(VisualNodesCount, x, x0, y0)
  247.     y0 = y0 - 30
  248.     IF (e <> -1) THEN
  249.         dxtmp = 8 * .5 * (LEN(Literal$(x)) + LEN(Literal$(e)))
  250.         IF (dxtmp < 30) THEN dxtmp = 30
  251.         CALL VisualListRecur(e, x0 + dxtmp, y0)
  252.     END IF
  253.     IF (s <> -1) THEN
  254.         CALL VisualListRecur(s, x0, y0)
  255.     END IF
  256.  
  257. SUB MoveSingleVisualNode (i AS INTEGER, x AS LONG, dx AS DOUBLE, dy AS DOUBLE)
  258.     DIM cx AS DOUBLE
  259.     DIM cy AS DOUBLE
  260.     cx = VisualNodes(i).BoxCenter.x
  261.     cy = VisualNodes(i).BoxCenter.y
  262.     CALL DefineVisualNode(i, x, cx + dx, cy + dy)
  263.  
  264. SUB MoveVisualNodesRecur (i AS INTEGER, x AS LONG, dx AS DOUBLE, dy AS DOUBLE)
  265.     DIM s AS LONG
  266.     DIM e AS LONG
  267.     DIM k AS INTEGER
  268.     DIM f AS INTEGER
  269.     s = Nodes(x).South
  270.     e = Nodes(x).East
  271.     CALL MoveSingleVisualNode(i, x, dx, dy)
  272.     IF (e <> -1) THEN
  273.         f = 0
  274.         FOR k = 1 TO VisualNodesCount
  275.             IF (VisualNodes(k).Reference = e) THEN
  276.                 f = 1
  277.                 EXIT FOR
  278.             END IF
  279.         NEXT
  280.         IF (f = 1) THEN
  281.             CALL MoveVisualNodesRecur(k, e, dx, dy)
  282.         END IF
  283.     END IF
  284.     IF (s <> -1) THEN
  285.         f = 0
  286.         FOR k = 1 TO VisualNodesCount
  287.             IF (VisualNodes(k).Reference = s) THEN
  288.                 f = 1
  289.                 EXIT FOR
  290.             END IF
  291.         NEXT
  292.         IF (f = 1) THEN
  293.             CALL MoveVisualNodesRecur(k, s, dx, dy)
  294.         END IF
  295.     END IF
  296.  
  297. SUB DefineVisualNode (i AS INTEGER, x AS LONG, cx AS DOUBLE, cy AS DOUBLE)
  298.     DIM h AS DOUBLE
  299.     DIM w AS DOUBLE
  300.     h = 22
  301.     w = 12 + 8 * LEN(Literal$(x))
  302.     VisualNodes(i).Reference = x
  303.     VisualNodes(i).BoxCenter.x = cx
  304.     VisualNodes(i).BoxCenter.y = cy
  305.     VisualNodes(i).BoxHeight = h
  306.     VisualNodes(i).BoxWidth = w
  307.     VisualNodes(i).CornerNE.x = cx + .5 * w
  308.     VisualNodes(i).CornerNE.y = cy + .5 * h
  309.     VisualNodes(i).CornerNW.x = cx - .5 * w
  310.     VisualNodes(i).CornerNW.y = cy + .5 * h
  311.     VisualNodes(i).CornerSE.x = cx + .5 * w
  312.     VisualNodes(i).CornerSE.y = cy - .5 * h
  313.     VisualNodes(i).CornerSW.x = cx - .5 * w
  314.     VisualNodes(i).CornerSW.y = cy - .5 * h
  315.     VisualNodes(i).AntennaN.x = cx
  316.     VisualNodes(i).AntennaN.y = cy + .5 * h + 3
  317.     VisualNodes(i).AntennaS.x = cx
  318.     VisualNodes(i).AntennaS.y = cy - .5 * h - 3
  319.     VisualNodes(i).AntennaE.x = cx + .5 * w + 3
  320.     VisualNodes(i).AntennaE.y = cy
  321.     VisualNodes(i).AntennaW.x = cx - .5 * w - 3
  322.     VisualNodes(i).AntennaW.y = cy
  323.  
  324. SUB DrawSingleNode (x AS LONG)
  325.     CALL clineb(VisualNodes(x).CornerNE.x, VisualNodes(x).CornerNE.y, VisualNodes(x).CornerSW.x, VisualNodes(x).CornerSW.y, _RGB32(255, 255, 255))
  326.     CALL cprintstring(VisualNodes(x).CornerNW.x + 6, VisualNodes(x).CornerNW.y - 4, Literal$(VisualNodes(x).Reference))
  327.  
  328. FUNCTION VisualNodeIndexFromReference (x AS LONG)
  329.     DIM TheReturn AS INTEGER
  330.     DIM j AS INTEGER
  331.     TheReturn = -1
  332.     FOR j = 1 TO VisualNodesCount
  333.         IF (VisualNodes(j).Reference = x) THEN
  334.             TheReturn = j
  335.             EXIT FOR
  336.         END IF
  337.     NEXT
  338.     VisualNodeIndexFromReference = TheReturn
  339.  
  340. SUB DrawWires (x AS INTEGER)
  341.     DIM i AS LONG
  342.     DIM k AS INTEGER
  343.     DIM s AS LONG
  344.     DIM e AS LONG
  345.     i = VisualNodes(x).Reference
  346.     s = Nodes(i).South
  347.     e = Nodes(i).East
  348.     IF (s <> -1) THEN
  349.         k = VisualNodeIndexFromReference(s)
  350.         CALL cline(VisualNodes(x).AntennaS.x, VisualNodes(x).AntennaS.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGB32(255, 255, 255))
  351.         CALL ccircle(VisualNodes(x).AntennaS.x, VisualNodes(x).AntennaS.y, 3, _RGB32(255, 255, 255))
  352.     END IF
  353.     IF (e <> -1) THEN
  354.         k = VisualNodeIndexFromReference(e)
  355.         CALL cline(VisualNodes(x).AntennaE.x, VisualNodes(x).AntennaE.y, VisualNodes(k).BoxCenter.x, VisualNodes(k).BoxCenter.y, _RGB32(255, 255, 255))
  356.         CALL ccircle(VisualNodes(x).AntennaE.x, VisualNodes(x).AntennaE.y, 3, _RGB32(255, 255, 255))
  357.     END IF
  358.  
  359. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  360. ' Cartesian graphics
  361. '
  362.  
  363. SUB cline (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  364.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2, -y2 + _HEIGHT / 2), col
  365.  
  366. SUB clineb (x1 AS DOUBLE, y1 AS DOUBLE, x2 AS DOUBLE, y2 AS DOUBLE, col AS _UNSIGNED LONG)
  367.     LINE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2)-(_WIDTH / 2 + x2, -y2 + _HEIGHT / 2), col, B
  368.  
  369. SUB ccircle (x1 AS DOUBLE, y1 AS DOUBLE, rad AS DOUBLE, col AS _UNSIGNED LONG)
  370.     CIRCLE (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), rad, col
  371.  
  372. SUB cpset (x1 AS DOUBLE, y1 AS DOUBLE, col AS _UNSIGNED LONG)
  373.     PSET (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), col
  374.  
  375. SUB cpaint (x1 AS DOUBLE, y1 AS DOUBLE, col1 AS _UNSIGNED LONG, col2 AS _UNSIGNED LONG)
  376.     PAINT (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), col1, col2
  377.  
  378. SUB cprintstring (x1 AS DOUBLE, y1 AS DOUBLE, a AS STRING)
  379.     '_PRINTSTRING (_WIDTH / 2 - (LEN(a) * 8) / 2, -y + _HEIGHT / 2), a
  380.     _PRINTSTRING (_WIDTH / 2 + x1, -y1 + _HEIGHT / 2), a
  381.  
  382. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  383. ' Demo cases:
  384. '
  385.  
  386. SUB DemoMerge
  387.     DIM TheName1 AS STRING
  388.     DIM TheName2 AS STRING
  389.     TheName1 = "top part"
  390.     TheName2 = "bottom part"
  391.  
  392.     DIM a AS LONG
  393.     DIM b AS LONG
  394.     a = NewLinkedList(TheName1)
  395.     a = LinkEast(a, NewStringNode("lambda"))
  396.     b = LinkEast(a, NewIntegerNode(4))
  397.     b = LinkSouth(b, NewIntegerNode(6))
  398.     a = NewUnitList("cow", NewIntegerNode(5))
  399.     a = NewLinkedList(TheName2)
  400.     a = LinkEast(a, NewStringNode("cos"))
  401.     b = LinkEast(a, NewStringNode("*"))
  402.     b = LinkEast(b, NewIntegerNode(3))
  403.     b = LinkSouth(b, NewStringNode("[1]"))
  404.     b = LinkSouth(b, CopyIntegerNode(Content("cow")))
  405.     b = LinkSouth(b, NewStringNode("[2]"))
  406.  
  407.     PRINT PrintLinkedList$(HeadId(TheName1))
  408.     PRINT PrintLinkedList$(HeadId(TheName2))
  409.     CALL BuildVisualList(HeadId(TheName1), 0, -100, .9 * _HEIGHT / 2)
  410.     CALL BuildVisualList(HeadId(TheName2), 0, -100, 0)
  411.     PRINT
  412.  
  413.     CALL Halt
  414.  
  415.     a = ListId(TheName2)
  416.     b = LinkedList(a).HeadNode
  417.     LinkedListRegister(a) = 0
  418.     IdentityRegister(b) = 0
  419.  
  420.     a = Nodes(LinkedList(ListId(TheName1)).HeadNode).East
  421.     b = Nodes(b).East
  422.     Nodes(b).North = a
  423.     Nodes(a).South = b
  424.  
  425.     PRINT PrintLinkedList$(HeadId(TheName1))
  426.     CALL BuildVisualList(HeadId(TheName1), 0, -100, .9 * _HEIGHT / 2)
  427.     PRINT
  428.  
  429.     CALL Halt
  430.  
  431.     a = Evaluate(HeadId(TheName1))
  432.  
  433.     PRINT PrintLinkedList$(HeadId(TheName1))
  434.     CALL BuildVisualList(HeadId(TheName1), 0, -100, .9 * _HEIGHT / 2)
  435.     PRINT
  436.  
  437.     CLS
  438.  
  439.     CALL UserLoop
  440.  
  441.     CLS
  442.  
  443.     CALL UserLoop
  444.  
  445.     a = DeleteLinkedList(ListId(TheName1))
  446.     a = DeleteLinkedList(ListId(TheName2))
  447.     a = DeleteLinkedList(ListId("cow"))
  448.  
  449.     PRINT
  450.     PRINT GarbageTest("")
  451.  
  452.     CALL Halt
  453.  
  454. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  455.  
  456. SUB DemoLambda
  457.     DIM TheName AS STRING
  458.     TheName = "Lambda Test"
  459.  
  460.     DIM a AS LONG
  461.     DIM b AS LONG
  462.     a = NewUnitList("cow", NewIntegerNode(7))
  463.     a = NewLinkedList(TheName)
  464.     a = LinkEast(a, NewStringNode("lambda"))
  465.     b = LinkEast(a, NewIntegerNode(4))
  466.     b = LinkSouth(b, NewIntegerNode(6))
  467.     a = LinkSouth(a, NewStringNode("cos"))
  468.     b = LinkEast(a, NewStringNode("*"))
  469.     b = LinkEast(b, NewIntegerNode(3))
  470.     b = LinkSouth(b, NewStringNode("[1]"))
  471.     b = LinkSouth(b, CopyIntegerNode(Content("cow")))
  472.     b = LinkSouth(b, NewStringNode("[2]"))
  473.  
  474.     PRINT PrintLinkedList$(HeadId(TheName))
  475.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  476.     PRINT
  477.  
  478.     CALL Halt
  479.  
  480.     a = Evaluate(HeadId(TheName))
  481.  
  482.     PRINT PrintLinkedList$(HeadId(TheName))
  483.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  484.     PRINT
  485.  
  486.     CLS
  487.  
  488.     CALL UserLoop
  489.  
  490.     a = DeleteLinkedList(ListId(TheName))
  491.     a = DeleteLinkedList(ListId("cow"))
  492.  
  493.     PRINT
  494.     PRINT GarbageTest("")
  495.  
  496.     CALL Halt
  497.  
  498.     CLS
  499.  
  500. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  501.  
  502. SUB DemoList
  503.     DIM TheName AS STRING
  504.     TheName = "List Test"
  505.  
  506.     DIM a AS LONG
  507.     DIM b AS LONG
  508.     a = NewLinkedList(TheName)
  509.     a = LinkEast(a, NewStringNode("cos"))
  510.     b = LinkEast(a, NewStringNode("three"))
  511.     b = LinkSouth(b, NewStringNode("four"))
  512.     b = LinkSouth(b, NewStringNode("five"))
  513.     b = LinkSouth(b, NewStringNode("six"))
  514.     b = LinkSouth(b, NewStringNode("seven"))
  515.     a = LinkSouth(a, NewStringNode("cos"))
  516.     b = LinkEast(a, NewIntegerNode(3))
  517.     b = LinkSouth(b, NewIntegerNode(4))
  518.     b = LinkSouth(b, NewIntegerNode(5))
  519.     b = LinkSouth(b, NewIntegerNode(6))
  520.     b = LinkSouth(b, NewIntegerNode(7))
  521.  
  522.     PRINT PrintLinkedList$(HeadId(TheName))
  523.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  524.     PRINT
  525.  
  526.     CALL Halt
  527.  
  528.     a = Evaluate(HeadId(TheName))
  529.  
  530.     PRINT PrintLinkedList$(HeadId(TheName))
  531.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  532.     PRINT
  533.  
  534.     CLS
  535.  
  536.     CALL UserLoop
  537.  
  538.     a = DeleteLinkedList(ListId(TheName))
  539.  
  540.     PRINT
  541.     PRINT GarbageTest("")
  542.  
  543.     CALL Halt
  544.  
  545.     CLS
  546.  
  547. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  548.  
  549. SUB DemoArithmetic
  550.     DIM ListNames(2) AS STRING
  551.     ListNames(1) = "Arithmetic Test1"
  552.     ListNames(2) = "Arithmetic Test2"
  553.  
  554.     DIM a AS LONG
  555.     DIM b AS LONG
  556.     a = NewLinkedList(ListNames(1))
  557.     a = LinkEast(a, NewStringNode("*"))
  558.     b = LinkEast(a, NewIntegerNode(3))
  559.     b = LinkSouth(b, NewIntegerNode(4))
  560.     a = LinkSouth(b, NewStringNode("cos"))
  561.     b = LinkEast(a, NewStringNode("+"))
  562.     b = LinkEast(b, NewIntegerNode(4))
  563.     b = LinkSouth(b, NewIntegerNode(7))
  564.     b = LinkSouth(a, NewIntegerNode(2))
  565.  
  566.     PRINT PrintLinkedList$(HeadId(ListNames(1)))
  567.     CALL BuildVisualList(HeadId(ListNames(1)), 0, -100, .9 * _HEIGHT / 2)
  568.     PRINT
  569.  
  570.     CALL Halt
  571.  
  572.     a = Evaluate(HeadId(ListNames(1)))
  573.  
  574.     PRINT PrintLinkedList$(HeadId(ListNames(1)))
  575.     CALL BuildVisualList(HeadId(ListNames(1)), 0, -100, .9 * _HEIGHT / 2)
  576.     PRINT
  577.  
  578.     CALL Halt
  579.  
  580.     a = NewLinkedList(ListNames(2))
  581.     a = LinkEast(a, NewStringNode("/"))
  582.     b = LinkEast(a, NewIntegerNode(3))
  583.     a = LinkSouth(b, NewStringNode("cos"))
  584.     b = LinkEast(a, NewStringNode("+"))
  585.     b = LinkEast(b, NewIntegerNode(4))
  586.     b = LinkSouth(b, NewDoubleNode(DoubleData(Nodes(Nodes(HeadId(ListNames(1))).East).Reference)))
  587.  
  588.     PRINT PrintLinkedList$(HeadId(ListNames(2)))
  589.     CALL BuildVisualList(HeadId(ListNames(2)), 0, -100, .9 * _HEIGHT / 2)
  590.     PRINT
  591.  
  592.     CALL Halt
  593.  
  594.     a = Evaluate(HeadId(ListNames(2)))
  595.  
  596.     PRINT PrintLinkedList$(HeadId(ListNames(2)))
  597.     CALL BuildVisualList(HeadId(ListNames(2)), 0, -100, .9 * _HEIGHT / 2)
  598.     PRINT
  599.  
  600.     CLS
  601.  
  602.     CALL UserLoop
  603.  
  604.     CLS
  605.  
  606.     CALL UserLoop
  607.  
  608.     a = DeleteLinkedList(ListId(ListNames(1)))
  609.     a = DeleteLinkedList(ListId(ListNames(2)))
  610.  
  611.     PRINT
  612.     PRINT GarbageTest("")
  613.  
  614.     CALL Halt
  615.  
  616.     CLS
  617.  
  618. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  619.  
  620. SUB DemoTreeEdit
  621.     DIM TheName AS STRING
  622.     TheName = "Tree Edit Test"
  623.  
  624.     DIM a AS LONG
  625.     DIM b AS LONG
  626.     DIM c AS LONG
  627.     a = NewLinkedList(TheName)
  628.     a = LinkEast(a, NewStringNode("QB64 Buddy"))
  629.     a = LinkEast(a, NewStringNode("Handle"))
  630.     b = LinkEast(a, NewStringNode("flukiluke"))
  631.     a = LinkSouth(a, NewStringNode("Name"))
  632.     b = LinkEast(a, NewStringNode("Luke C."))
  633.     a = LinkSouth(a, NewStringNode("Country"))
  634.     b = LinkEast(a, NewStringNode("Australia"))
  635.     c = LinkEast(b, NewStringNode("Locality"))
  636.     b = LinkEast(c, NewStringNode("Down Under"))
  637.     a = LinkSouth(a, NewStringNode("Birthyear"))
  638.     b = LinkEast(a, NewIntegerNode(1523))
  639.     c = LinkSouth(b, NewStringNode("May???"))
  640.  
  641.     PRINT PrintLinkedList$(HeadId(TheName))
  642.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  643.     PRINT
  644.  
  645.     PRINT "Inserting `Get it?' into list..."
  646.     a = InsertEast(SeekString("Down Under", HeadId(TheName), 1), NewStringNode("Get it?"))
  647.     PRINT "Adding new entry to bottom of list..."
  648.     a = InsertSouth(SeekString("QB64 Buddy", HeadId(TheName), 1), NewStringNode("QB64 Enemy"))
  649.     PRINT "Editing Birthyear..."
  650.     a = EditIntegerReference(StepUsing(SeekString("Birthyear", HeadId(TheName), 1), "e"), 1855)
  651.     PRINT "Deleting Name..."
  652.     a = DeleteNodes(SeekString("Name", HeadId(TheName), 1))
  653.     PRINT
  654.  
  655.     CALL Halt
  656.  
  657.     CLS
  658.  
  659.     PRINT PrintLinkedList$(HeadId(TheName))
  660.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  661.     PRINT
  662.  
  663.     CALL Halt
  664.  
  665.     CALL UserLoop
  666.  
  667.     a = DeleteLinkedList(ListId(TheName))
  668.  
  669.     PRINT
  670.     PRINT GarbageTest("")
  671.  
  672.     CALL Halt
  673.  
  674.     CLS
  675.  
  676. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  677.  
  678. SUB DemoTree
  679.     DIM TheName AS STRING
  680.     TheName = "Tree of Friends"
  681.  
  682.     DIM a AS LONG
  683.     DIM b AS LONG
  684.     DIM c AS LONG
  685.     DIM d AS LONG
  686.     a = NewLinkedList(TheName)
  687.     a = LinkEast(a, NewStringNode("QB64 Buddy")): d = a
  688.     a = LinkEast(a, NewStringNode("Handle"))
  689.     b = LinkEast(a, NewStringNode("SMcNeill"))
  690.     a = LinkSouth(a, NewStringNode("Name"))
  691.     b = LinkEast(a, NewStringNode("Steve SMcNeill"))
  692.     a = LinkSouth(a, NewStringNode("Country"))
  693.     b = LinkEast(a, NewStringNode("USA"))
  694.     c = LinkEast(b, NewStringNode("Locality"))
  695.     b = LinkEast(c, NewStringNode("Virginia"))
  696.     a = LinkSouth(a, NewStringNode("Birthyear"))
  697.     b = LinkEast(a, NewIntegerNode(1973))
  698.     c = LinkSouth(b, NewStringNode("May?"))
  699.     a = LinkSouth(d, NewStringNode("QB64 Buddy")): d = a
  700.     a = LinkEast(a, NewStringNode("Handle"))
  701.     b = LinkEast(a, NewStringNode("FellippeHeitor"))
  702.     a = LinkSouth(a, NewStringNode("Name"))
  703.     b = LinkEast(a, NewStringNode("Fellippe Heitor"))
  704.     a = LinkSouth(a, NewStringNode("Country"))
  705.     b = LinkEast(a, NewStringNode("Brazil"))
  706.     c = LinkEast(b, NewStringNode("Locality"))
  707.     b = LinkEast(c, NewStringNode("My <3"))
  708.     c = LinkEast(b, NewStringNode("JK, it's ___."))
  709.     a = LinkSouth(a, NewStringNode("Birthyear"))
  710.     b = LinkEast(a, NewIntegerNode(1983))
  711.     c = LinkSouth(b, NewStringNode("Sep?"))
  712.     b = LinkSouth(c, NewStringNode("... or was it May?"))
  713.     a = LinkSouth(d, NewStringNode("QB64 Buddy")): d = a
  714.     a = LinkEast(a, NewStringNode("Handle"))
  715.     b = LinkEast(a, NewStringNode("DanTurtle"))
  716.  
  717.     'CLS
  718.  
  719.     'PRINT PrintLinkedList$(HeadId(TheName))
  720.     'PRINT
  721.  
  722.     '' Query tests
  723.     'PRINT "Height:";
  724.     'PRINT SquareListHeight(ListId(TheName))
  725.     'PRINT "Steve's locality: ";
  726.     'PRINT Literal$(StepUsing(HeadId(TheName), "eesseee"))
  727.     'PRINT "Fellippe's locality: ";
  728.     'PRINT Literal$(StepUsing(HeadId(TheName), "esesseee"))
  729.     'PRINT "Fellippe's birth month: ";
  730.     'PRINT Literal$(StepUsing(JumpFrom(StepUsing(HeadId(TheName), "ese"), "s", 3), "es"))
  731.     'PRINT "Width of Fellippe's Country branch:";
  732.     'PRINT Measure(SeekString("Country", HeadId(TheName), 2), "e")
  733.     'PRINT "Height under Fellippe's Birthyear branch:";
  734.     'PRINT Measure(Nodes(SeekString("Birthyear", HeadId(TheName), 2)).East, "s")
  735.     'PRINT
  736.  
  737.     'CALL Halt
  738.  
  739.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  740.     'CALL UserLoop
  741.  
  742.     'a = DeleteLinkedList(ListId(TheName))
  743.  
  744.     'PRINT
  745.     'PRINT GarbageTest("")
  746.  
  747.     'CALL Halt
  748.  
  749. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  750. SUB DemoArray3D
  751.     CALL LoadArray3D("Three-Dimensional Array")
  752.     CALL QueryArray3D("Three-Dimensional Array")
  753.  
  754.  
  755. SUB LoadArray3D (TheName AS STRING)
  756.     DIM i AS INTEGER
  757.     DIM j AS INTEGER
  758.     DIM k AS INTEGER
  759.     DIM a AS LONG
  760.     DIM b AS LONG
  761.  
  762.     DIM TestArray3D(3, 2, 3) AS STRING
  763.     TestArray3D(1, 1, 1) = "one.one.one"
  764.     TestArray3D(1, 1, 2) = "one.one.two"
  765.     TestArray3D(1, 1, 3) = "one.one.three"
  766.     TestArray3D(1, 2, 1) = "one.two.one"
  767.     TestArray3D(1, 2, 2) = "one.two.two"
  768.     TestArray3D(1, 2, 3) = "one.two.three"
  769.     TestArray3D(2, 1, 1) = "two.one.one"
  770.     TestArray3D(2, 1, 2) = "two.one.two"
  771.     TestArray3D(2, 1, 3) = "two.one.three"
  772.     TestArray3D(2, 2, 1) = "two.two.one"
  773.     TestArray3D(2, 2, 2) = "two.two.two"
  774.     TestArray3D(2, 2, 3) = "two.two.three"
  775.     TestArray3D(3, 1, 1) = "three.one.one"
  776.     TestArray3D(3, 1, 2) = "three.one.two"
  777.     TestArray3D(3, 1, 3) = "three.one.three"
  778.     TestArray3D(3, 2, 1) = "three.two.one"
  779.     TestArray3D(3, 2, 2) = "three.two.two"
  780.     TestArray3D(3, 2, 3) = "three.two.three"
  781.     'TestArray3D(4, 1, 1) = "four.one.one"
  782.     'TestArray3D(4, 1, 2) = "four.one.two"
  783.     'TestArray3D(4, 1, 3) = "four.one.three"
  784.     'TestArray3D(4, 2, 1) = "four.two.one"
  785.     'TestArray3D(4, 2, 2) = "four.two.two"
  786.     'TestArray3D(4, 2, 3) = "four.two.three"
  787.  
  788.     ' Load 3D array as linked list
  789.     a = NewLinkedList(TheName)
  790.     FOR i = 1 TO UBOUND(TestArray3D, 1)
  791.         FOR j = 1 TO UBOUND(TestArray3D, 2)
  792.             FOR k = 1 TO UBOUND(TestArray3D, 3)
  793.                 IF ((i = 1) AND (j = 1) AND (k = 1)) THEN
  794.                     a = LinkEast(a, NewStringNode(TestArray3D(i, j, k)))
  795.                     b = a
  796.                 ELSE
  797.                     IF (k = 1) THEN
  798.                         a = LinkSouth(a, NewStringNode(TestArray3D(i, j, k)))
  799.                         b = a
  800.                     ELSE
  801.                         b = LinkEast(b, NewStringNode(TestArray3D(i, j, k)))
  802.                     END IF
  803.                 END IF
  804.             NEXT
  805.         NEXT
  806.     NEXT
  807.  
  808. SUB QueryArray3D (TheName AS STRING)
  809.     DIM a AS LONG
  810.     DIM k AS INTEGER
  811.  
  812.     PRINT PrintLinkedList$(HeadId(TheName))
  813.     CALL BuildVisualList(HeadId(TheName), 0, -100, .9 * _HEIGHT / 2)
  814.     PRINT
  815.     PRINT "Query tests:"
  816.     PRINT "Height:"; SquareListHeight(ListId(TheName))
  817.     PRINT "Width:"; SquareListWidth(ListId(TheName))
  818.     PRINT
  819.     PRINT "Typical FOR loop:"
  820.     FOR k = 1 TO Bottom(TheName)
  821.         PRINT Literal$(JumpFrom(Content(TheName), "s", k))
  822.     NEXT
  823.     PRINT
  824.     CALL Halt
  825.     CALL UserLoop
  826.     a = DeleteLinkedList(ListId(TheName))
  827.     PRINT
  828.     PRINT GarbageTest("")
  829.     CALL Halt
  830.  
  831.  
  832. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  833. ' Begin BM-component.
  834. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  835.  
  836. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  837. ' Processing
  838. '
  839.  
  840. FUNCTION Evaluate (x AS LONG)
  841.     DIM TheReturn AS LONG
  842.     DIM a AS LONG
  843.     DIM b AS LONG
  844.     a = x
  845.     b = -1
  846.     DO
  847.         a = EvalStep(FirstEmbedded(a))
  848.         IF (a = x) THEN EXIT DO
  849.         IF (a = b) THEN
  850.             a = Nodes(a).South
  851.             IF (a = -1) THEN
  852.                 EXIT DO
  853.             END IF
  854.         ELSE
  855.             b = a
  856.         END IF
  857.     LOOP
  858.     TheReturn = a
  859.     Evaluate = TheReturn
  860.  
  861. FUNCTION EvalStep (x AS LONG)
  862.     DIM TheReturn AS LONG
  863.     DIM SouthernId AS LONG
  864.     DIM NorthernId AS LONG
  865.     DIM FunctionId AS LONG
  866.     DIM i AS LONG
  867.     DIM j AS LONG
  868.     DIM k AS INTEGER
  869.     DIM n AS LONG
  870.     DIM s AS LONG
  871.     DIM RefSpecies AS STRING
  872.     DIM ReturnSpecies AS STRING
  873.     DIM ReturnInteger AS INTEGER
  874.     DIM ReturnString AS STRING
  875.     DIM ReturnDouble AS DOUBLE
  876.     DIM MultiPass AS INTEGER
  877.  
  878.     RefSpecies = ""
  879.     FunctionId = x
  880.     ReturnSpecies = ""
  881.     ReturnInteger = 0
  882.     ReturnString = ""
  883.     ReturnDouble = 0
  884.  
  885.     ' Pre-evaluation
  886.     IF (x <> -1) THEN
  887.         SouthernId = x
  888.         i = x
  889.         DO
  890.             n = Nodes(i).North
  891.             IF (n <> -1) THEN
  892.                 i = n
  893.             ELSE
  894.                 NorthernId = i
  895.                 EXIT DO
  896.             END IF
  897.         LOOP
  898.         FunctionId = Nodes(NorthernId).West
  899.         ReturnSpecies = Nodes(FunctionId).Species
  900.         SELECT CASE ReturnSpecies
  901.             CASE "integer"
  902.                 ReturnInteger = IntegerData(Nodes(FunctionId).Reference)
  903.             CASE "string"
  904.                 ReturnString = StringData(Nodes(FunctionId).Reference)
  905.             CASE "double"
  906.                 ReturnDouble = DoubleData(Nodes(FunctionId).Reference)
  907.         END SELECT
  908.     END IF
  909.  
  910.     ' Lambda substitution
  911.     i = NorthernId
  912.     DIM lf AS INTEGER
  913.     lf = 0
  914.     DO
  915.         IF (Nodes(i).Species = "string") THEN
  916.             IF (StringData(Nodes(i).Reference) = "[1]") THEN
  917.                 j = LambdaMatrix(LambdaIndex, 1)
  918.                 Nodes(i).Species = Nodes(j).Species
  919.                 Nodes(i).Reference = Nodes(j).Reference
  920.                 lf = 1
  921.             END IF
  922.             IF (StringData(Nodes(i).Reference) = "[2]") THEN
  923.                 j = LambdaMatrix(LambdaIndex, 2)
  924.                 Nodes(i).Species = Nodes(j).Species
  925.                 Nodes(i).Reference = Nodes(j).Reference
  926.                 lf = 1
  927.             END IF
  928.         END IF
  929.         IF (i = SouthernId) THEN
  930.             EXIT DO
  931.         ELSE
  932.             s = Nodes(i).South
  933.             i = s
  934.         END IF
  935.     LOOP
  936.     IF (lf = 1) THEN
  937.         FOR k = 1 TO LambdaArgCount(LambdaIndex)
  938.             j = Unlink(LambdaMatrix(LambdaIndex, k))
  939.         NEXT
  940.         LambdaArgCount(LambdaIndex) = 0
  941.         LambdaIndex = LambdaIndex - 1
  942.     END IF
  943.  
  944.     ' Determine return species
  945.     i = NorthernId
  946.     DO
  947.         IF (i = -1) THEN EXIT DO
  948.         IF (Nodes(i).Species = "string") THEN RefSpecies = "string"
  949.         IF ((Nodes(i).Species = "double") AND (RefSpecies <> "string")) THEN RefSpecies = "double"
  950.         IF ((Nodes(i).Species = "integer") AND (RefSpecies <> "string") AND (RefSpecies <> "double")) THEN RefSpecies = "integer"
  951.         i = Nodes(i).South
  952.     LOOP
  953.  
  954.     ' Single-pass evaluation
  955.     MultiPass = 0
  956.     SELECT CASE Literal$(FunctionId)
  957.         CASE "*"
  958.             MultiPass = 1
  959.             ReturnSpecies = RefSpecies
  960.             ReturnInteger = 1
  961.             ReturnDouble = 1
  962.         CASE "+"
  963.             MultiPass = 1
  964.             ReturnSpecies = RefSpecies
  965.             ReturnInteger = 0
  966.             ReturnDouble = 0
  967.         CASE "/"
  968.             MultiPass = 0
  969.             SELECT CASE Nodes(NorthernId).Species
  970.                 CASE "integer"
  971.                     ReturnSpecies = "double"
  972.                     SELECT CASE Nodes(SouthernId).Species
  973.                         CASE "integer"
  974.                             ReturnDouble = IntegerData(Nodes(NorthernId).Reference) / IntegerData(Nodes(SouthernId).Reference)
  975.                         CASE "double"
  976.                             ReturnDouble = IntegerData(Nodes(NorthernId).Reference) / DoubleData(Nodes(SouthernId).Reference)
  977.                     END SELECT
  978.                 CASE "string"
  979.                     ReturnSpecies = "string"
  980.                     ReturnString = Literal$(NorthernId) + "/" + Literal$(SouthernId)
  981.                 CASE "double"
  982.                     ReturnSpecies = "double"
  983.                     SELECT CASE Nodes(SouthernId).Species
  984.                         CASE "integer"
  985.                             ReturnDouble = DoubleData(Nodes(NorthernId).Reference) / IntegerData(Nodes(SouthernId).Reference)
  986.                         CASE "double"
  987.                             ReturnDouble = DoubleData(Nodes(NorthernId).Reference) / DoubleData(Nodes(SouthernId).Reference)
  988.                     END SELECT
  989.             END SELECT
  990.             i = Unlink(NorthernId)
  991.             i = Unlink(SouthernId)
  992.         CASE "cos"
  993.             IF (NorthernId = SouthernId) THEN
  994.                 MultiPass = 0
  995.                 i = NorthernId
  996.                 SELECT CASE Nodes(i).Species
  997.                     CASE "integer"
  998.                         ReturnSpecies = "double"
  999.                         ReturnDouble = COS(IntegerData(Nodes(i).Reference))
  1000.                     CASE "string"
  1001.                         ReturnSpecies = "string"
  1002.                         ReturnString = "cos" + "(" + Literal$(i) + ")"
  1003.                     CASE "double"
  1004.                         ReturnSpecies = "double"
  1005.                         ReturnDouble = COS(DoubleData(Nodes(i).Reference))
  1006.                 END SELECT
  1007.                 i = Unlink(i)
  1008.             ELSE
  1009.                 MultiPass = 1
  1010.                 ReturnSpecies = "string"
  1011.                 ReturnString = "(" + "cos" + ")"
  1012.             END IF
  1013.         CASE "lambda"
  1014.             MultiPass = 1
  1015.             LambdaIndex = LambdaIndex + 1
  1016.             ReturnSpecies = "string"
  1017.             ReturnString = "(" + "lambda" + ")"
  1018.         CASE "(" + "lambda" + ")"
  1019.             '
  1020.     END SELECT
  1021.  
  1022.     ' Multi-pass evaluation
  1023.     IF (MultiPass = 1) THEN
  1024.         i = NorthernId
  1025.         DO
  1026.             SELECT CASE Literal$(FunctionId)
  1027.                 CASE "*"
  1028.                     SELECT CASE ReturnSpecies
  1029.                         CASE "integer"
  1030.                             SELECT CASE Nodes(i).Species
  1031.                                 CASE "integer"
  1032.                                     ReturnInteger = ReturnInteger * IntegerData(Nodes(i).Reference)
  1033.                                 CASE "double"
  1034.                                     ReturnInteger = ReturnInteger * DoubleData(Nodes(i).Reference)
  1035.                             END SELECT
  1036.                         CASE "string"
  1037.                             ReturnString = ReturnString + Literal$(i)
  1038.                         CASE "double"
  1039.                             SELECT CASE Nodes(i).Species
  1040.                                 CASE "integer"
  1041.                                     ReturnDouble = ReturnDouble * IntegerData(Nodes(i).Reference)
  1042.                                 CASE "double"
  1043.                                     ReturnDouble = ReturnDouble * DoubleData(Nodes(i).Reference)
  1044.                             END SELECT
  1045.                     END SELECT
  1046.                     IF (i = SouthernId) THEN
  1047.                         i = Unlink(i)
  1048.                         EXIT DO
  1049.                     ELSE
  1050.                         s = Nodes(i).South
  1051.                         i = Unlink(i)
  1052.                         i = s
  1053.                     END IF
  1054.                 CASE "+"
  1055.                     SELECT CASE ReturnSpecies
  1056.                         CASE "integer"
  1057.                             SELECT CASE Nodes(i).Species
  1058.                                 CASE "integer"
  1059.                                     ReturnInteger = ReturnInteger + IntegerData(Nodes(i).Reference)
  1060.                                 CASE "double"
  1061.                                     ReturnInteger = ReturnInteger + DoubleData(Nodes(i).Reference)
  1062.                             END SELECT
  1063.                         CASE "string"
  1064.                             ReturnString = ReturnString + Literal$(i)
  1065.                         CASE "double"
  1066.                             SELECT CASE Nodes(i).Species
  1067.                                 CASE "integer"
  1068.                                     ReturnDouble = ReturnDouble + IntegerData(Nodes(i).Reference)
  1069.                                 CASE "double"
  1070.                                     ReturnDouble = ReturnDouble + DoubleData(Nodes(i).Reference)
  1071.                             END SELECT
  1072.                     END SELECT
  1073.                     IF (i = SouthernId) THEN
  1074.                         i = Unlink(i)
  1075.                         EXIT DO
  1076.                     ELSE
  1077.                         s = Nodes(i).South
  1078.                         i = Unlink(i)
  1079.                         i = s
  1080.                     END IF
  1081.                 CASE "cos"
  1082.                     SELECT CASE Nodes(i).Species
  1083.                         CASE "integer"
  1084.                             Nodes(i).Species = "double"
  1085.                             Nodes(i).Reference = NewDoubleData(COS(IntegerData(Nodes(i).Reference)))
  1086.                         CASE "string"
  1087.                             Nodes(i).Reference = NewStringData("cos" + "(" + Literal$(i) + ")")
  1088.                         CASE "double"
  1089.                             Nodes(i).Species = "double"
  1090.                             Nodes(i).Reference = NewDoubleData(COS(DoubleData(Nodes(i).Reference)))
  1091.                     END SELECT
  1092.                     IF (i = SouthernId) THEN
  1093.                         EXIT DO
  1094.                     ELSE
  1095.                         s = Nodes(i).South
  1096.                         i = s
  1097.                     END IF
  1098.                 CASE "lambda"
  1099.                     LambdaArgCount(LambdaIndex) = LambdaArgCount(LambdaIndex) + 1
  1100.                     LambdaMatrix(LambdaIndex, LambdaArgCount(LambdaIndex)) = i
  1101.                     IF (i = SouthernId) THEN
  1102.                         EXIT DO
  1103.                     ELSE
  1104.                         s = Nodes(i).South
  1105.                         i = s
  1106.                     END IF
  1107.             END SELECT
  1108.         LOOP
  1109.     END IF
  1110.  
  1111.     SELECT CASE ReturnSpecies
  1112.         CASE "integer"
  1113.             Nodes(FunctionId).Species = ReturnSpecies
  1114.             Nodes(FunctionId).Reference = NewIntegerData(ReturnInteger)
  1115.         CASE "string"
  1116.             Nodes(FunctionId).Species = ReturnSpecies
  1117.             Nodes(FunctionId).Reference = NewStringData(ReturnString)
  1118.         CASE "double"
  1119.             Nodes(FunctionId).Species = ReturnSpecies
  1120.             Nodes(FunctionId).Reference = NewDoubleData(ReturnDouble)
  1121.     END SELECT
  1122.  
  1123.     TheReturn = FunctionId
  1124.     EvalStep = TheReturn
  1125.  
  1126. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1127. ' Seek and recall
  1128. '
  1129.  
  1130. FUNCTION FirstEmbedded (x AS LONG)
  1131.     DIM TheReturn AS LONG
  1132.     TheReturn = MostEmbeddedRecur(x, -1)
  1133.     FirstEmbedded = TheReturn
  1134.  
  1135. FUNCTION MostEmbeddedRecur (x AS LONG, y AS LONG)
  1136.     DIM TheReturn AS LONG
  1137.     DIM s AS LONG
  1138.     DIM e AS LONG
  1139.     s = Nodes(x).South
  1140.     e = Nodes(x).East
  1141.     IF (e <> -1) THEN
  1142.         TheReturn = MostEmbeddedRecur(e, y)
  1143.     END IF
  1144.     IF (s <> -1) THEN
  1145.         TheReturn = MostEmbeddedRecur(s, y)
  1146.     END IF
  1147.     IF (e = -1) AND (s = -1) AND (y = -1) THEN
  1148.         y = x
  1149.     END IF
  1150.     TheReturn = y
  1151.     MostEmbeddedRecur = TheReturn
  1152.  
  1153. FUNCTION SeekString (t AS STRING, x AS LONG, r AS INTEGER)
  1154.     DIM TheReturn AS LONG
  1155.     DIM s AS LONG
  1156.     DIM e AS LONG
  1157.     TheReturn = -1
  1158.     s = Nodes(x).South
  1159.     e = Nodes(x).East
  1160.     IF (StringData(Nodes(x).Reference) = t) THEN
  1161.         TheReturn = x
  1162.         r = r - 1
  1163.     ELSE
  1164.         IF (e <> -1) AND (r > 0) THEN
  1165.             TheReturn = SeekString(t, e, r)
  1166.         END IF
  1167.         IF (s <> -1) AND (r > 0) THEN
  1168.             TheReturn = SeekString(t, s, r)
  1169.         END IF
  1170.     END IF
  1171.     SeekString = TheReturn
  1172.  
  1173. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1174. ' Navigation
  1175. '
  1176.  
  1177. FUNCTION Content (t AS STRING)
  1178.     DIM TheReturn AS LONG
  1179.     TheReturn = Nodes(HeadId(t)).East
  1180.     Content = TheReturn
  1181.  
  1182. FUNCTION Bottom (t AS STRING)
  1183.     DIM TheReturn AS LONG
  1184.     TheReturn = -1 + Measure(Content(t), "s")
  1185.     Bottom = TheReturn
  1186.  
  1187. FUNCTION ListId (t AS STRING)
  1188.     DIM TheReturn AS LONG ' Change this to int. ?
  1189.     DIM k AS LONG
  1190.     TheReturn = -1
  1191.     FOR k = 1 TO UBOUND(LinkedList)
  1192.         IF (LinkedList(k).Label = t) THEN
  1193.             TheReturn = k
  1194.             EXIT FOR
  1195.         END IF
  1196.     NEXT
  1197.     ListId = TheReturn
  1198.  
  1199. FUNCTION HeadId (t AS STRING)
  1200.     DIM TheReturn AS LONG
  1201.     TheReturn = LinkedList(ListId(t)).HeadNode
  1202.     HeadId = TheReturn
  1203.  
  1204. FUNCTION JumpFrom (x AS LONG, t AS STRING, r AS INTEGER)
  1205.     DIM TheReturn AS LONG
  1206.     TheReturn = x
  1207.     IF (r > 0) THEN
  1208.         SELECT CASE t
  1209.             CASE "n"
  1210.                 TheReturn = JumpFrom(Nodes(x).North, "n", r - 1)
  1211.             CASE "s"
  1212.                 TheReturn = JumpFrom(Nodes(x).South, "s", r - 1)
  1213.             CASE "e"
  1214.                 TheReturn = JumpFrom(Nodes(x).East, "e", r - 1)
  1215.             CASE "w"
  1216.                 TheReturn = JumpFrom(Nodes(x).West, "w", r - 1)
  1217.         END SELECT
  1218.     END IF
  1219.     JumpFrom = TheReturn
  1220.  
  1221. FUNCTION StepUsing (x AS LONG, t AS STRING)
  1222.     DIM TheReturn AS LONG
  1223.     DIM i AS LONG
  1224.     DIM j AS LONG
  1225.     DIM k AS INTEGER
  1226.     i = x
  1227.     FOR k = 1 TO LEN(t)
  1228.         SELECT CASE MID$(t, k, 1)
  1229.             CASE "n"
  1230.                 j = Nodes(i).North
  1231.                 IF (j <> -1) THEN i = j
  1232.             CASE "s"
  1233.                 j = Nodes(i).South
  1234.                 IF (j <> -1) THEN i = j
  1235.             CASE "e"
  1236.                 j = Nodes(i).East
  1237.                 IF (j <> -1) THEN i = j
  1238.             CASE "w"
  1239.                 j = Nodes(i).West
  1240.                 IF (j <> -1) THEN i = j
  1241.         END SELECT
  1242.     NEXT
  1243.     TheReturn = i
  1244.     StepUsing = TheReturn
  1245.  
  1246. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1247. ' Internal metrics
  1248. '
  1249.  
  1250. FUNCTION SquareListHeight (x AS INTEGER)
  1251.     DIM TheReturn AS INTEGER
  1252.     TheReturn = Measure(Nodes(LinkedList(x).HeadNode).East, "s")
  1253.     SquareListHeight = TheReturn
  1254.  
  1255. FUNCTION SquareListWidth (x AS INTEGER)
  1256.     DIM TheReturn AS INTEGER
  1257.     TheReturn = Measure(Nodes(LinkedList(x).HeadNode).East, "e")
  1258.     SquareListWidth = TheReturn
  1259.  
  1260. FUNCTION Measure (x AS LONG, t AS STRING)
  1261.     DIM TheReturn AS INTEGER
  1262.     TheReturn = CountSteps(x, -1, t)
  1263.     Measure = TheReturn
  1264.  
  1265. FUNCTION CountSteps (x AS LONG, y AS LONG, t AS STRING)
  1266.     DIM TheReturn AS INTEGER
  1267.     DIM k AS LONG
  1268.     TheReturn = 0
  1269.     SELECT CASE t
  1270.         CASE "n"
  1271.             k = Nodes(x).North
  1272.         CASE "s"
  1273.             k = Nodes(x).South
  1274.         CASE "e"
  1275.             k = Nodes(x).East
  1276.         CASE "w"
  1277.             k = Nodes(x).West
  1278.     END SELECT
  1279.     IF (k = y) THEN
  1280.         TheReturn = TheReturn + 1
  1281.     ELSE
  1282.         IF (k <> -1) THEN
  1283.             TheReturn = TheReturn + 1 + CountSteps(k, y, t)
  1284.         END IF
  1285.     END IF
  1286.     CountSteps = TheReturn
  1287.  
  1288. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1289. ' Printing and Reporting
  1290. '
  1291.  
  1292. FUNCTION GarbageTest$ (t AS STRING)
  1293.     DIM TheReturn AS STRING
  1294.     DIM a AS LONG
  1295.     DIM k AS INTEGER
  1296.     TheReturn = t
  1297.     TheReturn = TheReturn + "Begin garbage test..." + CHR$(10)
  1298.     FOR k = 1 TO UBOUND(LinkedListRegister)
  1299.         IF (LinkedListRegister(k) <> 0) THEN
  1300.             PRINT LinkedList(k).Label
  1301.             CALL BuildVisualList(LinkedList(k).HeadNode, 0, .8 * _WIDTH * (RND - .5), .8 * _HEIGHT * (RND - .5))
  1302.         END IF
  1303.     NEXT
  1304.     FOR k = 1 TO UBOUND(IdentityRegister)
  1305.         IF (IdentityRegister(k) <> 0) THEN
  1306.             a = IdentityRegister(k)
  1307.             TheReturn = TheReturn + Literal$(a) + " (" + Literal$(Nodes(a).North) + "," + Literal$(Nodes(a).South) + "," + Literal$(Nodes(a).East) + "," + Literal$(Nodes(a).West) + ")" '+ CHR$(10)
  1308.             TheReturn = TheReturn + CHR$(10)
  1309.         END IF
  1310.     NEXT
  1311.     TheReturn = TheReturn + "End garbage test..." + CHR$(10)
  1312.     GarbageTest$ = TheReturn
  1313.  
  1314. FUNCTION PrintLinkedList$ (x AS LONG)
  1315.     DIM TheReturn AS STRING
  1316.     DIM t AS STRING
  1317.     t = ListNodesRecur$(0, x)
  1318.     TheReturn = LEFT$(t, LEN(t) - 1)
  1319.     PrintLinkedList$ = TheReturn
  1320.  
  1321. FUNCTION ListNodesRecur$ (i AS INTEGER, x AS LONG)
  1322.     DIM TheReturn AS STRING
  1323.     DIM s AS LONG
  1324.     DIM e AS LONG
  1325.     s = Nodes(x).South
  1326.     e = Nodes(x).East
  1327.     TheReturn = TheReturn + SPACE$(i) + Literal$(x) + CHR$(10)
  1328.     IF (e <> -1) THEN
  1329.         TheReturn = TheReturn + ListNodesRecur$(i + 2, e)
  1330.     END IF
  1331.     IF (s <> -1) THEN
  1332.         TheReturn = TheReturn + ListNodesRecur$(i, s)
  1333.     END IF
  1334.     ListNodesRecur$ = TheReturn
  1335.  
  1336. FUNCTION Literal$ (x AS LONG)
  1337.     DIM TheReturn AS STRING
  1338.     TheReturn = ""
  1339.     IF (x <> -1) THEN
  1340.         SELECT CASE Nodes(x).Species
  1341.             CASE "integer"
  1342.                 TheReturn = LTRIM$(RTRIM$(STR$(IntegerData(Nodes(x).Reference))))
  1343.             CASE "string"
  1344.                 TheReturn = StringData(Nodes(x).Reference)
  1345.             CASE "double"
  1346.                 TheReturn = LTRIM$(RTRIM$(STR$(DoubleData(Nodes(x).Reference))))
  1347.         END SELECT
  1348.     END IF
  1349.     Literal$ = TheReturn
  1350.  
  1351. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1352. ' Linked list construction
  1353. '
  1354.  
  1355. FUNCTION NewUnitList (t AS STRING, x AS LONG)
  1356.     DIM TheReturn AS LONG
  1357.     DIM k AS LONG
  1358.     TheReturn = NewLinkedList(t)
  1359.     k = LinkEast(TheReturn, x)
  1360.     NewUnitList = TheReturn
  1361.  
  1362. FUNCTION NewLinkedList (t AS STRING)
  1363.     DIM i AS LONG
  1364.     DIM k AS LONG
  1365.     k = NewStringNode(t)
  1366.     i = NextOpenLinkedList(1)
  1367.     LinkedListRegister(i) = i
  1368.     LinkedList(i).Label = StringData(Nodes(k).Reference)
  1369.     LinkedList(i).HeadNode = k
  1370.     NewLinkedList = k
  1371.  
  1372. FUNCTION NextOpenLinkedList (x AS LONG)
  1373.     DIM TheReturn AS LONG
  1374.     DIM k AS LONG
  1375.     TheReturn = -1
  1376.     FOR k = x TO UBOUND(LinkedListRegister)
  1377.         IF (LinkedListRegister(k) = 0) THEN
  1378.             TheReturn = k
  1379.             EXIT FOR
  1380.         END IF
  1381.     NEXT
  1382.     NextOpenLinkedList = TheReturn
  1383.  
  1384. FUNCTION LinkSouth (n AS LONG, s AS LONG)
  1385.     DIM TheReturn AS LONG
  1386.     Nodes(s).North = n
  1387.     Nodes(n).South = s
  1388.     TheReturn = s
  1389.     LinkSouth = TheReturn
  1390.  
  1391. FUNCTION LinkEast (w AS LONG, e AS LONG)
  1392.     DIM TheReturn AS LONG
  1393.     Nodes(w).East = e
  1394.     Nodes(e).West = w
  1395.     TheReturn = e
  1396.     LinkEast = TheReturn
  1397.  
  1398. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1399. ' Linked list editing
  1400. '
  1401. FUNCTION InsertSouth (n AS LONG, x AS LONG)
  1402.     DIM s AS LONG
  1403.     s = Nodes(n).South
  1404.     Nodes(n).South = x
  1405.     Nodes(x).North = n
  1406.     Nodes(x).South = s
  1407.     IF (s <> -1) THEN
  1408.         Nodes(s).North = x
  1409.     END IF
  1410.     InsertSouth = x
  1411.  
  1412. FUNCTION InsertEast (w AS LONG, x AS LONG)
  1413.     DIM e AS LONG
  1414.     e = Nodes(w).East
  1415.     Nodes(w).East = x
  1416.     Nodes(x).West = w
  1417.     Nodes(x).East = e
  1418.     IF (e <> -1) THEN
  1419.         Nodes(e).West = x
  1420.     END IF
  1421.     InsertEast = x
  1422.  
  1423. FUNCTION Unlink (x AS LONG)
  1424.     DIM n AS LONG
  1425.     DIM s AS LONG
  1426.     DIM e AS LONG
  1427.     DIM w AS LONG
  1428.     n = Nodes(x).North
  1429.     s = Nodes(x).South
  1430.     e = Nodes(x).East
  1431.     w = Nodes(x).West
  1432.     IF (n <> -1) THEN Nodes(n).South = s
  1433.     IF (s <> -1) THEN Nodes(s).North = n
  1434.     IF (e <> -1) THEN Nodes(e).West = w
  1435.     IF (w <> -1) THEN Nodes(w).East = e
  1436.     IdentityRegister(x) = 0
  1437.     Unlink = x
  1438.  
  1439. FUNCTION DeleteNodes (x AS LONG)
  1440.     DIM TheReturn AS LONG
  1441.     DIM e AS LONG
  1442.     e = Nodes(x).East
  1443.     IF (e <> -1) THEN
  1444.         TheReturn = DeleteRecur(e)
  1445.     END IF
  1446.     TheReturn = Unlink(x)
  1447.     DeleteNodes = TheReturn
  1448.  
  1449. FUNCTION DeleteRecur (x AS LONG)
  1450.     DIM TheReturn AS LONG
  1451.     DIM s AS LONG
  1452.     DIM e AS LONG
  1453.     s = Nodes(x).South
  1454.     e = Nodes(x).East
  1455.     IF (e <> -1) THEN
  1456.         TheReturn = DeleteRecur(e)
  1457.     END IF
  1458.     IF (s <> -1) THEN
  1459.         TheReturn = DeleteRecur(s)
  1460.     END IF
  1461.     TheReturn = Unlink(x)
  1462.     DeleteRecur = TheReturn
  1463.  
  1464. FUNCTION DeleteLinkedList (x AS INTEGER)
  1465.     DIM TheReturn AS LONG
  1466.     LinkedListRegister(x) = 0
  1467.     TheReturn = DeleteRecur(LinkedList(x).HeadNode)
  1468.     DeleteLinkedList = TheReturn
  1469.  
  1470. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1471. ' Node creation
  1472. '
  1473.  
  1474. FUNCTION NextOpenIdentity (x AS LONG)
  1475.     DIM TheReturn AS LONG
  1476.     DIM k AS LONG
  1477.     TheReturn = -1
  1478.     FOR k = x TO UBOUND(IdentityRegister)
  1479.         IF (IdentityRegister(k) = 0) THEN
  1480.             TheReturn = k
  1481.             EXIT FOR
  1482.         END IF
  1483.     NEXT
  1484.     NextOpenIdentity = TheReturn
  1485.  
  1486. FUNCTION NewNode (x AS LONG, t AS STRING, r AS LONG)
  1487.     DIM i AS LONG
  1488.     i = NextOpenIdentity(x)
  1489.     IdentityRegister(i) = i
  1490.     Nodes(i).Identity = i
  1491.     Nodes(i).Species = t
  1492.     Nodes(i).Reference = r
  1493.     Nodes(i).North = -1
  1494.     Nodes(i).South = -1
  1495.     Nodes(i).East = -1
  1496.     Nodes(i).West = -1
  1497.     NewNode = i
  1498.  
  1499. FUNCTION CopyIntegerNode (x AS LONG)
  1500.     CopyIntegerNode = NewIntegerNode(IntegerData(Nodes(x).Reference))
  1501.  
  1502. FUNCTION NewIntegerNode (x AS INTEGER)
  1503.     NewIntegerNode = NewNode(1, "integer", NewIntegerData(x))
  1504.  
  1505. FUNCTION NewStringNode (x AS STRING)
  1506.     NewStringNode = NewNode(1, "string", NewStringData(x))
  1507.  
  1508. FUNCTION NewDoubleNode (x AS DOUBLE)
  1509.     NewDoubleNode = NewNode(1, "double", NewDoubleData(x))
  1510.  
  1511. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1512. ' Node editing
  1513. '
  1514.  
  1515. FUNCTION EditIntegerReference (i AS LONG, x AS INTEGER)
  1516.     DIM z AS LONG
  1517.     z = NewIntegerData(x)
  1518.     Nodes(i).Reference = z
  1519.     EditIntegerReference = z
  1520.  
  1521. FUNCTION EditStringReference (i AS LONG, x AS STRING)
  1522.     DIM z AS LONG
  1523.     z = NewStringData(x)
  1524.     Nodes(i).Reference = z
  1525.     EditStringReference = z
  1526.  
  1527. FUNCTION EditDoubleReference (i AS LONG, x AS DOUBLE)
  1528.     DIM z AS LONG
  1529.     z = NewDoubleData(x)
  1530.     Nodes(i).Reference = z
  1531.     EditDoubleReference = z
  1532.  
  1533. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1534. ' Data assimilation
  1535. '
  1536.  
  1537. FUNCTION NewIntegerData (x AS INTEGER)
  1538.     DIM TheReturn AS LONG
  1539.     DIM k AS LONG
  1540.     TheReturn = -1
  1541.     FOR k = 1 TO UBOUND(IntegerData)
  1542.         IF (IntegerData(k) = x) THEN
  1543.             TheReturn = k
  1544.             EXIT FOR
  1545.         END IF
  1546.     NEXT
  1547.     IF (TheReturn = -1) THEN
  1548.         REDIM _PRESERVE IntegerData(UBOUND(IntegerData) + 1)
  1549.         IntegerData(UBOUND(IntegerData)) = x
  1550.         TheReturn = UBOUND(IntegerData)
  1551.     END IF
  1552.     NewIntegerData = TheReturn
  1553.  
  1554. FUNCTION NewStringData (x AS STRING)
  1555.     DIM TheReturn AS LONG
  1556.     DIM k AS LONG
  1557.     TheReturn = -1
  1558.     FOR k = 1 TO UBOUND(StringData)
  1559.         IF (StringData(k) = x) THEN
  1560.             TheReturn = k
  1561.             EXIT FOR
  1562.         END IF
  1563.     NEXT
  1564.     IF (TheReturn = -1) THEN
  1565.         REDIM _PRESERVE StringData(UBOUND(StringData) + 1)
  1566.         StringData(UBOUND(Stringdata)) = x
  1567.         TheReturn = UBOUND(StringData)
  1568.     END IF
  1569.     NewStringData = TheReturn
  1570.  
  1571. FUNCTION NewDoubleData (x AS DOUBLE)
  1572.     DIM TheReturn AS LONG
  1573.     DIM k AS LONG
  1574.     TheReturn = -1
  1575.     FOR k = 1 TO UBOUND(DoubleData)
  1576.         IF (DoubleData(k) = x) THEN
  1577.             TheReturn = k
  1578.             EXIT FOR
  1579.         END IF
  1580.     NEXT
  1581.     IF (TheReturn = -1) THEN
  1582.         REDIM _PRESERVE DoubleData(UBOUND(DoubleData) + 1)
  1583.         DoubleData(UBOUND(DoubleData)) = x
  1584.         TheReturn = UBOUND(DoubleData)
  1585.     END IF
  1586.     NewDoubleData = TheReturn
  1587.  
  1588. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1589. ' End BM-component.
  1590. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  1591.  
You're not done when it works, you're done when it's right.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: A new take on arrays and data
« Reply #24 on: April 30, 2020, 11:12:45 pm »
LOOK I MADE A BI-PLANE!

 
biplane.jpg
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #25 on: May 01, 2020, 05:34:25 am »
Haha I totally see it!
You're not done when it works, you're done when it's right.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #26 on: May 10, 2020, 06:34:29 pm »
Hello all,

This project is approaching its "final" update with respect to the main code base. Recently I've gone full-tilt in the GUI direction, and the end result is, go figure, possibly useful! I figured I'd post it. I'm at a point where there is too much to explain about the hows and whys of this program. That will have to come at a slightly later date with a formal write-up, with real sections, etc.

For now though, I give you something to play with. Most of the controls are self-explanatory. As usual you can mash ESC through the whole thing, but I beckon you to resize to full screen, discover what the mouse does, play with some buttons, etc.

For those who are joining late, this is a program that demonstrates how (and provides the tools) to dispense with old-fashioned arrays and rethink your future data structures as linked lists, allowing for a crazy range of flexibility.

Yes, the text-carrying visual nodes look like street signs. I said it.

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

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: A new take on arrays and data
« Reply #27 on: May 18, 2020, 11:10:32 am »
Hello folks,

This project is a point where the best thing for it is public scrutiny and input. This is a bit hard because, despite the volumes of prose above this very reply, I haven't fully explained what's going on here. While I make no real attempt to do so in this thread, I think this can start to speak for itself if I post a few trivial uses. So here's one:

Code: QB64: [Select]
  1.  
  2. REM $Include: 'SoftArrays.bi'
  3.  
  4. PRINT "Task 1/2: Store the name and country of three friends in 2D Array:"
  5.  
  6. DIM Regular2DArray(3, 2) AS STRING
  7. Regular2DArray(1, 1) = "Steve"
  8. Regular2DArray(1, 2) = "USA"
  9. Regular2DArray(2, 1) = "Fellippe"
  10. Regular2DArray(2, 2) = "Brazil"
  11. Regular2DArray(3, 1) = "Luke"
  12. Regular2DArray(3, 2) = "Australia"
  13. FOR i = 1 TO UBOUND(Regular2DArray, 1)
  14.     FOR j = 1 TO UBOUND(Regular2DArray, 2)
  15.         PRINT Regular2DArray(i, j);
  16.         IF (j < UBOUND(Regular2DArray, 2)) THEN PRINT " -> ";
  17.     NEXT
  18.     PRINT
  19. PRINT "Printing 2,2 entry: "; Regular2DArray(2, 2)
  20.  
  21. PRINT "..."
  22.  
  23. PRINT "Task 2/2: Store the name and country of three friends in Soft Array:"
  24.  
  25. a = NewSoftArray("Friends")
  26. a = LinkEast(a, NewTextNode("Steve"))
  27. b = LinkEast(a, NewTextNode("USA"))
  28. a = LinkSouth(a, NewTextNode("Fellippe"))
  29. b = LinkEast(a, NewTextNode("Brazil"))
  30. a = LinkSouth(a, NewTextNode("Luke"))
  31. b = LinkEast(a, NewTextNode("Australia"))
  32. PRINT PrintSoftArray(SoftArrayID("Friends"))
  33. PRINT "Printing 2,2 entry: ";
  34. a = JumpFrom(Content("Friends"), "s", 1)
  35. b = JumpFrom(a, "e", 1)
  36. PRINT Literal$(b)
  37.  
  38.  
  39. REM $Include: 'SoftArrays.bm'
  40.  

In the above you can see the task being accomplished twice. You can also start to imagine the trade-offs between the methods. Yes, it is less trivial to traverse a soft array as opposed to a hard one; certain things are harder than usual, certain things are easier. What's lovely is this framework does not dominate your main loop or anything silly like that.

If you want to undergo the formality of actually running that code, the most sensible way to get the bi/bm files is through github:

https://github.com/wfbarnes/SoftArrays

But for Pete, I'll attach them at the bottom. Of course, the completely optional Soft Array Editor is there too. This should give you a feel for what kind of control you can have over your data, once this idea is mastered.
* SoftArrayDemo.bas (Filesize: 1.26 KB, Downloads: 117)
* SoftArrays.bi (Filesize: 2.02 KB, Downloads: 132)
* SoftArrays.bm (Filesize: 30.08 KB, Downloads: 132)
* SoftArrayEditor.bas (Filesize: 37.37 KB, Downloads: 148)
You're not done when it works, you're done when it's right.