Menu

Inca

2019-07-01
2019-07-07
  • Yet Another Troll

    I cannot load a program into the Windows 1.27-58-unstable build running on Windows 10 32-bit. [Version 10.0.17763.593] The console simply quits with no error message. Trying to load the examples\demo.bas also quits.

     

    Last edit: Yet Another Troll 2019-07-01
    • Markus Hoffmann

      Markus Hoffmann - 2019-07-01

      Is it possible to enter commands (like XRUN?)

       
  • Markus Hoffmann

    Markus Hoffmann - 2019-07-01

    Ups. I have not noticed this. I have no idea what was wrong. Maybe I should roll out the more stable older versions 1.26-57 (without unstable) first.

     
    • Yet Another Troll

      Both XLOAD and XRUN also quit. I once got XRUN to return a file not found error without quitting but can't repeat it. LOAD will quit even when given a nonexistent file name. EDIT also just quits, possibly after creating a temp file. Commands adjacent to but not actually involving file I/O like ? DIR$(0) appear to run correctly. FSFIRST/FSNEXT also appear to work,

      > ver
      X11-BASIC Version: 1.27 Jun 30 2019 09:30:03
      > ? dir$(0)
      C:\Program Files\X11-Basic
      > ? fsfirst$(".", "*")
      - bas.ico
      > ? fsnext$()
      d contrib
      > ? fsnext$()
      d doc
      > ? fsnext$()
      d examples
      > ? fsnext$()
      - new.bas.~~~
      >
      

      That new.bas.~~~ temp file has since disappeared before I thought to navigate to it in Explorer to see if it contained anything. What deleted it?

       

      Last edit: Yet Another Troll 2019-07-01
  • Markus Hoffmann

    Markus Hoffmann - 2019-07-01

    new.bas.~~~ is generated by an EDIT command. It is just a temporary file.
    Concerning this error: I think I have found it. (The crash manifested only on the WINDOWS version, al though the error was also in the linux version). It was a bug in the LOAD mechanism. It was introduced with the dynamic stack handling.
    I have released new files for WINDOWS. Thanks for testing.
    However, even in the 1.27-58-unstable release I do see an error on WINDOWS:
    run the compiler, select demo.bas, select option "1" and during saving the .exe file I get a segmentation fault. I think this is because of some file permissions not set to write on C:/Program Files or so. It should produce a more readable error. Do you get this error as well?

     

    Last edit: Markus Hoffmann 2019-07-01
    • Yet Another Troll

      LOAD is working now. Thank you for your quick response! I'm afraid I haven't worked much with the compiler in Windows, mainly in Android, but I do know that Windows really, really doesn't want the program files directories to be written to by anything except installers and hotfixes since the introduction of NT 3.1 and NTFS twenty five years ago, even though cheating by twiddling directory permissions is common. W10 does set the TMP and TEMP environment variables to reasonable directories for temp files. I'll check 8.1 later.

       
    • Yet Another Troll

      One of my string space stress testers now appears to fail at an interesting line,

      16777216        100000  0.053   16777216        100000  83      3.023
      33554432        2000000 0.094   33554432        2000000 43      3.062
      67108864        4000000 0.188   67108864        4000000 22      3.093
      134217728       8000000 0.422   134217728       8000000 10      3.031
      268435456       ERROR at line 6: ** 1 - Segmentation fault
          pc-1  :   Temp% = Len(S$) * 2
      --> pc=6 :   Print Temp%, Hex$(Temp%),
          pc+1  :   Flush
      ** PROGRAM-STOP
      Terminate batch job (Y/N)?
      

      Why at the PRINT and not at the ADD doing awful, awful things to the string memory? Was that last allocation of 8 bytes by HEX$ or 12/16 by PRINT for a buffer enough to push the house of cards over?

      #!/usr/bin/xbasic
      
      Program Stringb0rk
       S$ = Chr$(30)
       Do
        Temp% = Len(S$) * 2
        Print Temp%, Hex$(Temp%),
        Flush
        Start = Timer
        ' S$ = S$ + S$ ! Space$(Temp%)
        Add S$, S$
        Print Round(Timer - Start, 8),
        Flush
        Pause 1 ! Allow Android to catch up with itself?
        VPS% = VarPtr(S$)
        Mask% = 0xFF
        Count% = 0
        Start = Timer
        Finish = Start + 3
        While Timer < Finish
         Temp% = Len(S$)
         ' Temp% = VarPtr(S$)
         ' Temp% = LPeek(Temp% - 4)
         ' Temp% = Asc(Mid$(S$, 2, 1)) And 0xFF
         ' Temp% = Peek(VPS% + 2 - 1) And Mask%
         Inc Count%
         ' Flush
        Wend
        Print Temp%, Hex$(Temp%), Count%, Timer - Start
        Flush
        ' Pause 5
        Temp% = VarPtr(S$)
        Add Temp%, LPeek(Temp% - 4)
        ' For i% = Temp% - 32 To Temp% + 4
        '  Print Hex$(Peek(i%) And 0xFF, 2); " ";
        '  Flush
        ' Next i%
        ' Print
       Loop
      End
      
       
    • Yet Another Troll

      xbbc works well when used in my user profile directory, but xbc complains about not finding xbvm:

      C:\Users\trollollio>"\Program Files\X11-Basic\xbbc.exe" -o Desktop\p.b -v "Desktop\0 Palindromic 3.bas"
      388     lines.
      1       procedures.
      1       labels.
      32      variables.
      62      relocations.
      --> Desktop\p.b [Info: BC_VERSION=1271
        Size of   Text-Segment: 3452
        Size of roData-Segment: 444
        Size of   Data-Segment: 0
        Size of    bss-Segment: 188
        Size of String-Segment: 256
        Size of Symbol-Segment: 1368 (114 symbols)
      ] done.
      
      C:\Users\trollollio>"\Program Files\X11-Basic\xbc.exe"
      Current working directory: C:\Users\foste
      virtual machine:   xbvm.exe
      bytecode compiler: xbbc.exe
      input file:
      xbc: ERROR: xbvm.exe not found.
      
      C:\Users\trollollio>
      
       
      • Markus Hoffmann

        Markus Hoffmann - 2019-07-03

        It looks for it in the directory from which xbc was called. That is C:\Users\trollollio

         
        • Yet Another Troll

          I tried running xbc.exe in the C:\Program Files\X11-Basic directory,

          031A8A30: 01 02 00 2f 5b 00 00 00 98 00 00 00 01 02 d1 01  .../[...ÿ......
          031A8A40: 5e 00 00 00 a0 00 00 00 01 02 00 2c 62 00 00 00  ^...á......,b...
          031A8A50: a8 00 00 00 01 02 d1 01 66 00 00 00 b0 00 00 00  ¿......f......
          031A8A60: 01 02 00 29 6a 00 00 00 b8 00 00 00 00 00 d1 01  ...)j.........
          031A8A70: 00 00 00 00 ca 01 00 00 00 00 00 26 00 00 00 00  ..........&....
          031A8A80: 92 02 00 00 00 00 d1 01 00 00 00 00 bf 02 00 00  Æ.............
          031A8A90: 00 00 00 23 00 00 00 00 e8 02 00 00 00 00 d1 01  ...#....Φ......
          031A8AA0: 00 00 00 00 e8 02 00 00                          ....Φ...
          Keydown: 100
          Scancode: 0x20, Name: d, Unicode: d (0x0064)
          Keydown: 101
          Scancode: 0x12, Name: e, Unicode: e (0x0065)
          Keydown: 109
          Scancode: 0x32, Name: m, Unicode: m (0x006D)
          Keydown: 111
          Scancode: 0x18, Name: o, Unicode: o (0x006F)
          saving ./demo.exe       817800  bytes.
          ERROR at offset $c68: ** 1 - Segmentation fault
          PC negativ !
          ** PROGRAM-STOP
          
          C:\Program Files\X11-Basic>
          
           
          • Markus Hoffmann

            Markus Hoffmann - 2019-07-07

            Aha, thank you. Another bug. I could not see it, because on my WINDOWS machine (which I rarely use) ther was a permission denied error when saving the .exe. I am not sure on which version this bug showed up. I> fear that it has been there unseen for a long time....

             
  • Markus Hoffmann

    Markus Hoffmann - 2019-07-01

    Looks like the 24bit address space is exaustet (32bit WINDOWS in reallity only 24bit?) I dont know. On Linux the program continues until all 2GBytes RAm plus some SWAP space is eaten up, Then the program was killed by the OS.

     
    • Yet Another Troll

      I'm using a cheap Vulcan tablet. 2GB RAM, 32GB system drive, maybe no swap at all.

      This reminds me of the time in the early 90s I was trying a Sieve of Eratosthenes to find all primes between 3 and 0xFFFFFFFF on a 25MHz i486 with 16MB RAM in SCO Xenix/386 GT 2.3.4. I had a spare 1GB SCSI drive just lying around I could dedicate to swap, so...

      SCO tech support was very interested in the kernel quirks that turned up.

       

      Last edit: Yet Another Troll 2019-07-01
    • Yet Another Troll

      At least compiled programs can allocate integer matrices of at least 14401, 14401 but less than 14501, 14501.

      C:\Program Files\X11-Basic>contrib\ansicon xbasic
      **********************************************************
      *     sdlxbasic                     V.1.27              *
      *                       by Markus Hoffmann 1997-2019 (c) *
      ***  sdl la      gmp         snd                       ***
      * version date:            Mon Jul  1 15:04:58 CEST 2019 *
      * library V.1.27 date:     Mon Jul  1 15:04:58 CEST 2019 *
      **********************************************************
      
      > load "\users\trollollio\desktop\p.b"
      > run
      How long? 14400
      Allocated 14400 bytes in 0.004999999999995
      Corpus$ initialized in 0.096
      Sanity checked in 0.096
      0x31720204 bytes of monster matrix allocated in 35.986
      Row 2333    249.225
      

      What's strange is Task Manager shows the memory use is 320MB and climbing while the program is still in this loop which only works with string expressions in the Print statements,

      Dim Lookup%(N% + 1, N% + 1) ! This doesn't seem too terribly bad
       Clr Lookup%()
      
       Print "0x"; Hex$(((N% + 1) ^ 2) * 4); " bytes of ";
       Print "monster matrix allocated in "; Timer - Start
       ' Flush
      
       Clr i%, j%, k%, l%, VPC%
      
       VPC% = VarPtr(Corpus$)
      
       For i% = 1 To N%
        Print Chr$(13); "Row "; i%; " ";
        For j% = 1 To N%
      
         ' k% = Asc(Mid$(Corpus$, i%, 1))
         ' l% = Asc(Mid$(Corpus$, N% - j% + 1, 1))
         k% = Peek(VPC% + i% - 1)
         l% = Peek(VPC% + N% - j% + 1 - 1)
      
         If (Not Alpha%(k%)) Or (Not Alpha%(l%)) Then
          Print "Bad chars from Corpus$?", k%, l%
          Stop
         Else If k% = l% Then
          Lookup%(i%, j%) = Lookup%(i% - 1, j% - 1) + 1
         Else If Lookup%(i% - 1, j%) > Lookup%(i%, j% - 1) Then
          Lookup%(i%, j%) = Lookup%(i% - 1, j%)
         Else
          Lookup%(i%, j%) = Lookup%(i%, j% - 1)
         EndIf
      
        Next j%
      
        Print "   "; Round(Timer - Start, 3); "        ";
       Next i%
      
       Print
       Print Lookup%(N%, N%); " length of longest palindromic subsequence(s),"
      
       Print "Found length in "; Timer - Start
      

      ...and we have a BSOD in the recursive backtracking part of the code. Actual recursion depth was about 1260 and memory usage approaching 900MB because of the hash table of unique longest palindromic subsequences.

       

      Last edit: Yet Another Troll 2019-07-03
    • Yet Another Troll

      I'm currently trying to get around my cheap 32-bit Windows tablets' address and swap space issues by switching from a (N% + 1) ^ 2 matrix to an array of strings, only a few of which are actually in memory at any time. I was inspired by section 9.6 of the 1972 DEC BASIC PLUS manual, starting on page 131. There are interesting forgotten ideas in ancient software. However, instead of the entire matrix being mapped to one file, each row is currently being quick and dirty BLOADed and BSAVEd to individual files in ENV$("tmp") with an equally quick and dirty LRU algorithm and then mangled using LPEEK and LPOKE.

      The crazy begins with with Function Lookup%(),

      #!/usr/bin/ybasic
      
      Program Palindromic
       ShowK
       Input "How long? ", N%
       HideK
      
       Start = Timer
      
       Alpha$ = "GATTACA"
       ' Alpha$ = "non~EXO xenon"
       ' Alpha$ = "Able was I, ere I saw Elba."
       ' Alpha$ = "xxEva, can I see beezies ~~ in a cave???"
       ' Alpha$ = "!!A MAN. A PLAN. A CANAL. PANAMA!"
      
       Alpha$ = Upper$(Alpha$)
       LenA% = Len(Alpha$)
      
       If Glob(Alpha$, "*[-{}]*") Then
        Print "Forbidden characters in Alpha$"
        Stop
       EndIf
      
       ' Belt, suspenders, drones, crane, cargo helicopter, orbital skyhook
       Dim Alpha%(256)
       Clr Alpha%()
       For i% = 1 To Len(Alpha$)
        ' Parallelizable, but would it actually be worth it?
        Alpha%(Asc(Mid$(Alpha$, i%, 1))) = True
       Next i%
      
       Corpus$ = String$(N%, "-") ! No sentinels this time
      
       Print "Allocated "; Len(Corpus$); " bytes in "; Timer - Start
      
       Clr i%, j%, k%, VPA%, VPC%
      
       ' Randomize
      
       ' Watch out on 64-bit
       VPA% = VarPtr(Alpha$)
       VPC% = VarPtr(Corpus$)
       For i% = 1 To N%
        If (i% And 0xFFF) = 0 Then
         Print " "; i%; "  "; Chr$(13);
         ' Flush
        EndIf
        ' Parallelizable, I guess
        ' Repeat
         ' RANDOM sometimes b0rks in Winblows
         j% = Random(LenA%)
        ' Until (0 = j%) Or (j% < LenA%)
        ' k% = Asc(Mid$(Alpha$, j% + 1, 1))
        k% = Peek(VPA% + j% + 1 - 1)
        ' Caution, this sanity check adds significant overhead
        If Not Alpha%(k%) ! InStr(Alpha$, Chr$(k%)) = 0 Then
         Print "Invalid character at 0x"; Hex$(VPA%); " + "; j%, k%
         Stop
        EndIf
        ' Mid$(Corpus$, i%, 1) = Chr$(k%)
        Poke VPC% + i% - 1, k%
       Next i%
      
       Print "Corpus$ initialized in "; Timer - Start
      
       If N% <= 600 Then
        Print "'"; Corpus$; "'"
       EndIf
      
       If Glob(Corpus$, "*[!" + Alpha$ + "]*") Then
        Print "Invalid characters!"
        Stop
       EndIf
      
       Print "Sanity checked in "; Timer - Start
      
       ' Bottom-up algorithm blatantly ripped off from:
       ' https://www.techiedelight.com/longest-palindromic-subsequence-using-dynamic-programming/
      
       If N% < LenA% Then
        Print "'"; Alpha$; "'"
        Corpus$ = Upper$(Alpha$)
        N% = Len(Corpus$)
       EndIf
      
       If N% <= 600 Then
        Print "'"; Corpus$; "'"
       EndIf
      
       ' Dim Lockup%(N% + 1, N% + 1) ! This doesn't seem too terribly bad
       ' Clr Lockup%()
       Dim LookRows$(N% + 1)
       Dim LookFlag%(N% + 1)
       Dim LookLRUs%(N% + 1)
       Clr LookLRU%, LookLoad%
       LookTemp$ = Env$("tmp") + "/Palindromic-" + Str$(Timer) + "-"
      
       Print Chr$(34); LookTemp$; Chr$(34)
      
       ' Print "0x"; Hex$(((N% + 1) ^ 2) * 4); " bytes of ";
       Print "stub matrix allocated in "; Timer - Start
       ' Flush
      
       Clr i%, j%, k%, l%, VPC%
      
       VPC% = VarPtr(Corpus$)
      
       For i% = 1 To N%
        Print Chr$(13); "Row "; i%; " ";
        For j% = 1 To N%
      
         ' k% = Asc(Mid$(Corpus$, i%, 1))
         ' l% = Asc(Mid$(Corpus$, N% - j% + 1, 1))
         k% = Peek(VPC% + i% - 1)
         l% = Peek(VPC% + N% - j% + 1 - 1)
      
         If (Not Alpha%(k%)) Or (Not Alpha%(l%)) Then
          Print "Bad chars from Corpus$?", k%, l%
          Stop
         Else If k% = l% Then
          @LetLookup%(i%, j%, @Lookup%(i% - 1, j% - 1) + 1)
         Else If @Lookup%(i% - 1, j%) > @Lookup%(i%, j% - 1) Then
          @LetLookup%(i%, j%, @Lookup%(i% - 1, j%))
         Else
          @LetLookup%(i%, j%, @Lookup%(i%, j% - 1))
         EndIf
      
        Next j%
      
        Print "   "; Round(Timer - Start, 3); "        ";
       Next i%
      
       Print
       Print @Lookup%(N%, N%); " length of longest palindromic subsequence(s),"
      
       Print "Found length in "; Timer - Start
      
       ' Even more Globals???
      
       Dim H%(128) ! Hash table for S$(), size must be a power of two
       Dim S$(16)  ! DYNAMIC, Duplicated string table for StringInsanity
       Dim C%(16)  ! DYNAMIC, Open hashing chains for S$() and H%()
      
       HMask% = UBound(H%()) - 1
       ArrayFill H%(), -1
       Clr S$(), C%()
       SCount% = 0
      
       ' Still more Globals, call stack limits are nasty
      
       Clr R$, PalindromeCount%, MaxCallDepth%, MaxActualCallDepth%
      
       GoSub StringInsanity(N%, N%, 0, 0)
      
       Print PalindromeCount%, SCount%, MaxCallDepth%, MaxActualCallDepth%
      
       Print "Found some/all/most? in "; Timer - Start
      
       Print "OK"
      End
      
      Function Lookup%(Row%, Col%)
       ' Return Lockup%(Row%, Col%)
       LFR% = LookFlag%(Row%)
       If 0 ! (Row% < 0) Or (Row% > N%) Or (Col% < 0) Or (Col% > N%) Then
        ' Subscript out of range!
        Stop
       Else If LFR% And 2 Then
        ' Row is currently in memory
        ! No-op
       Else If LFR% = 0 Then
        ' No columns in this row have been written to
        Return 0
       Else If (LFR% And 2) = 0 Then
        ' Row is not currently in memory
        @DumpRows
        @LoadRow(Row%)
       Else ! Impossible
        Stop
       EndIf
       Inc LookLRU%
       LookLRUs%(Row%) = LookLRU%
       VPRow% = VarPtr(LookRows$(Row%))
       Return LPeek(VPRow% + ShL(Col%, 2))
      EndFunction
      
      Procedure LetLookup%(Row%, Col%, NewValue%)
       ' Let Lockup%(Row%, Col%) = NewValue%
       LFR% = LookFlag%(Row%)
       If 0 ! (Row% < 0) Or (Row% > N%) Or (Col% < 0) Or (Col% > N%) Then
        ' Subscript out of range!
        Stop
       Else If LFR% And 2 Then
        ' Row is currently in memory
        ! No-op
       Else If (LFR% And 2) = 0 Then
        ' Row is not currently in memory
        @DumpRows
        @LoadRow(Row%)
        LFR% = LookFlag%(Row%)
       Else ! Impossible
        Stop
       EndIf
       Inc LookLRU%
       LookLRUs%(Row%) = LookLRU%
       LookFlag%(Row%) = LFR% Or 1
       VPRow% = VarPtr(LookRows$(Row%))
       LPoke VPRow% + ShL(Col%, 2), NewValue%
      Return
      
      Procedure LoadRow(Row%)
       LFR% = LookFlag%(Row%)
       If LFR% And 2 Then
        ' Row is already in memory
        ! No-op
       Else If LFR% And 4 Then
        ' Load row from disk
        LookRows$(Row%) = Space$(ShL(N% + 1, 2))
        If Size(LookTemp$ + Str$(Row%) + ".temp") <> ShL(N% + 1, 2) Then
         Stop
        EndIf
        VPRow% = VarPtr(LookRows$(Row%))
        BLoad LookTemp$ + Str$(Row%) + ".temp", VPRow%
        LookFlag%(Row%) = LFR% Or 2
        Inc LookLoad%
       Else If LFR% = 0 Then
        ' Brand new row
        LookRows$(Row%) = String$(ShL(N% + 1, 2), Chr$(0))
        LookFlag%(Row%) = LFR% Or 2
        Inc LookLoad%
       Else ! Impossible
        Stop
       EndIf
       If Len(LookRows$(Row%)) <> ShL(N% + 1, 2) Then
        Stop
       EndIf
      Return
      
      Procedure DumpRows()
       Local LRU%, LRURow%, i%
       While LookLoad% > 4
        LRU% = 0x7FFFFFFF
        LRURow% = LRU%
        For i% = 0 To N%
         If (LookFlag%(i%) And 2) = 0 Then
          ' Row not loaded
          ! No-op
         Else If LookLRUs%(i%) < LRU% Then
          LRU% = LookLRUs%(i%)
          LRURow% = i%
         EndIf
        Next i%
        If LRU% = 0x7FFFFFFF Then
         Stop
        Else If LookFlag%(LRURow%) And 1 Then
         VPRow% = VarPtr(LookRows$(LRURow%))
         BSave LookTemp$ + Str$(LRURow%) + ".temp", VPRow%, Len(LookRows$(LRURow%))
         LookFlag%(LRURow%) = (LookFlag%(LRURow%) Or 4) And Not 1
        EndIf
        Clr LookRows$(LRURow%)
        LookFlag%(LRURow%) = LookFlag%(LRURow%) And Not 2
        Dec LookLoad%
       Wend
      Return
      
      ' IN     C$, N%, i%, j%, R$, CallDepth%
      ' OUT    NIL
      ' IN/OUT PalindromeCount%, MaxCallDepth%, MaxActualCallDepth%
      ' COMMON Alpha%(), Lookup%(), S$(), H%(), C%(), SCount%
      
      Procedure StringInsanity(i%, j%, CallDepth%, ActualCallDepth%)
       ' Local VPC%, VPR%
       ' Local k%, l%, m%
       ' Local KeepGoing%, PalindromeOK%
       Local LenR%
       ' Global Alpha%()
      
       Inc ActualCallDepth%
       If ActualCallDepth% > MaxActualCallDepth% Then
        MaxActualCallDepth% = ActualCallDepth%
        'Print MaxActualCallDepth%, MaxCallDepth%
       EndIf
      
      TailCallElimination:
      
       Inc CallDepth%
       If CallDepth% > MaxCallDepth% Then
        MaxCallDepth% = CallDepth%
       EndIf
      
       Print "  "; ActualCallDepth%; " "; CallDepth%; " ";
       Print MaxActualCallDepth%; " "; MaxCallDepth%;
       Print "  "; Chr$(13);
       ' Flush
      
       VPC% = VarPtr(Corpus$)
      
       If (i% = 0) Or (j% = 0) Then
        ' We should have a palindromic subsequence to print
      
        ' Have we already seen this one before?
      
        Hash% = CRC(R$) And HashMask%
        Prev% = 0xDEAFBEEF ! -1
        Curr% = H%(Hash%)
        Do
         Exit If Curr% < 0
         Exit If S$(Curr%) = R$
         Prev% = Curr%
         Curr% = C%(Curr%)
        Loop
      
        If Curr% >= 0 Then
         ' This is a duplicate
      
         If Prev% >= 0 Then
          ' Move the found duplicate string up to the front
          ' of the hash chain in case of repeated searches
          C%(Prev%) = C%(Curr%)
          C%(Curr%) = H%(Hash%)
          H%(Hash%) = Curr%
         EndIf
      
         Print " DUP ";
         ' Print "'"; R$; "'  "; Hash%; " "; Prev%; " "; Curr%; "     ";
         ' Print Chr$(13);
      
        Else If Curr% < 0 Then
         ' Not a duplicate!
      
         If SCount% = UBound(S$()) Then
          Print "*";
          ' Flush
          Dim S$(SCount% + ShR(SCount%, 2) + 4) ! REDIM PRESERVE
          Dim C%(SCount% + ShR(SCount%, 2) + 4) ! REDIM PRESERVE
          Print "*";
          ' Flush
         EndIf
      
         S$(SCount%) = R$
         C%(SCount%) = H%(Hash%)
         H%(Hash%) = SCount%
         Inc SCount%
      
         Inc PalindromeCount%
         Print PalindromeCount%; "  '"; R$; "'  "; Timer - Start
      
         ' Is it palindromic?
         k% = 1
         l% = Len(R$)
         VPR% = VarPtr(R$)
         KeepGoing% = (l% = @Lookup%(N%, N%))
         PalindromeOK% = (l% = @Lookup%(N%, N%))
         While KeepGoing%
          If Not (k% < l%) Then
           PalindromeOK% = True
           KeepGoing% = False
          Else If (Not Alpha%(Peek(VPR% + k% - 1))) Or (Not Alpha%(Peek(VPR% + l% - 1))) Then
           Print "Bad character(s) at", k%, l%
           Stop
          Else If Not (Peek(VPR% + k% - 1) = Peek(VPR% + l% - 1)) Then
           PalindromeOK% = False
           KeepGoing% = False
          Else
           Inc k%
           Dec l%
          EndIf
         Wend
         If Not PalindromeOK% Then
          Print
          Print PalindromeOK%, Len(R$), k%, l%, "'"; R$; "'"
          Stop
         EndIf
      
         ' Is it a subsequence of Corpus$ ?
         Print "{"; Corpus$; "}"
         Clr k%, l%, m%
         For k% = 1 To Len(R$)
          m% = InStr(Corpus$, Mid$(R$, k%, 1), l% + 1)
          If Not (l% < m%) Then
           Stop
          EndIf
          If l% = 0 Then
           While l% < m%
            Print " ";
            Inc l%
           Wend
          Else
           Inc l%
           While l% < m%
            Print " ";
            Inc l%
           Wend
          EndIf
          Print "|";
          l% = m%
         Next k%
         Print
         Clr k%, l%, m%
         For k% = 1 To Len(R$)
          m% = InStr(Corpus$, Mid$(R$, k%, 1), l% + 1)
          If Not (l% < m%) Then
           Stop
          EndIf
          If l% = 0 Then
           Inc l%
           While l% < m%
            Print " ";
            Inc l%
           Wend
           Print "'";
          Else
           Inc l%
           While l% < m%
            Print "-";
            Inc l%
           Wend
          EndIf
          Print Mid$(R$, k%, 1);
          l% = m%
         Next k%
         Print "'"
      
        Else
         ' Impossible!
         Print
         Print "DEAD CODE"
         Stop
        EndIf
      
        i% = 0x7FFFFFFF
        j% = 0x80000000
      
        'Print i%, j%,
        'Flush
      
       Else If Peek(VPC% + i% - 1) = Peek(VPC% + N% - j% + 1 - 1) Then
        ' R$ = R$ + Mid$(C$, i%, 1)
        Add R$, Chr$(Peek(VPC% + i% - 1))
        k% = @Lookup%(N%, N%) - Len(R$) + 1
        l% = Len(R$)
        Clr PalindromeOK%
        If Not (k% < l%) Then
         PalindromeOK% = True
        Else If Mid$(R$, k%, 1) = Mid$(R$, l%, 1) Then
         PalindromeOK% = True
        Else
         PalindromeOK% = False
        EndIf
        If Not PalindromeOK% Then
         Print "'"; R$; "' NOT OK", i%, j%
         Stop
        Else If k% < l% Then
         ' Print "'"; R$; "' OK"
         Add R$, Reverse$(Left$(R$, @Lookup%(N%, N%) - Len(R$)))
         Clr i%, j%
         GoTo TailCallElimination
        Else
         ' Print "'"; R$; "' ???"
         ' GoSub StringInsanity(C$, N%, i% - 1, j% - 1, R$)
         Dec i%
         Dec j%
         GoTo TailCallElimination
        EndIf
        ' Flush
      
       Else If @Lookup%(i% - 1, j%) > @Lookup%(i%, j% - 1) Then
        ' Should more compilers recognize tail recursion
        ' GoSub StringInsanity(C$, N%, i% - 1, j%, R$)
        Dec i%
        GoTo TailCallElimination
      
       Else If @Lookup%(i%, j% - 1) > @Lookup%(i% - 1, j%) Then
        ' and turn it into a GOTO
        ' GoSub StringInsanity(C$, N%, i%, j% - 1, R$)
        Dec j%
        GoTo TailCallElimination
      
       Else
        ' Finally, some non-tail recursion
        ' Print "Actual recursive call", i% - 1, j%
        ' Obvious SPAWN thread candidate is obvious
        LenR% = Len(R$)
        If 1 ! ActualCallDepth% < 465 Then ! RECURSION DEPTH GUARD
         GoSub StringInsanity(i% - 1, j%, CallDepth%, ActualCallDepth%)
        EndIf
        If LenR% < Len(R$) Then
         Print " Trimming R$ back to "; l%; Space$(20); Chr$(13);
         ' Flush
         R$ = Left$(R$, LenR%)
        Else If LenR% > Len(R$) Then
         Stop
        EndIf
        ' ...and back to the tail recursion
        ' GoSub StringInsanity(C$, N%, i%, j% - 1, R$)
        Dec j%
        GoTo TailCallElimination
       EndIf
      Return
      
       
      • Markus Hoffmann

        Markus Hoffmann - 2019-07-07

        Yea, I had forseen the MMAP function in X11-Basic for this, But I think I have never really used it, so I cannot say, if it is useful or not.

         
        • Yet Another Troll

          I saw the references to map, mmap, msync, and unmap in chapter 9 of the 1.27 manual, but no documentation for map in chapter 7. They do look very useful for simulating truly giant memory structures.

           
          • Markus Hoffmann

            Markus Hoffmann - 2019-07-07

            Yes, UNMAP und MSYNC are already implemented, but MMAP is not. (for some reason I have forgotten).

             
            • Yet Another Troll

              Is it because you're thinking of a DEC BASIC-PLUS-ish DIM# command and huge virtualized matrix support in both row-major and column-major ordering so operations such as MAT * won't completely thrash the swap? See sections 7.6 and 9.6,

              http://bitsavers.informatik.uni-stuttgart.de/pdf/dec/pdp11/rsts/V04/DEC-11-ORBPA-A-D_BASIC-PLUS_LangMan_Oct72.pdf

               
              • Markus Hoffmann

                Markus Hoffmann - 2019-07-07

                No, not really. I was rather thinking of MATLAB like matrix functions and also recusive definitions (matrix of matricies, etc...) X11-Basic is prepared for this in the sense of that the concept and the way it is implemented would more easily allow this. However, the implementation is still stub, because the concept of matrix of anything was not so useful, or at least I have not needed it so far.

                 
                • Yet Another Troll

                  Are you looking into beating Coppersmith-Winograd?

                  Multiplying matrices faster than Coppersmith-Winograd, V. Vassilevska Williams STOC 2012 [to come]
                  https://dl.acm.org/citation.cfm?id=2214056

                  Is your recursive array definition idea compatible with my bounds checked array sub-range idea for sorting?

                   

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.