coding challenge - codecaddy multiline

Just starting out? Need help? Post your questions and find answers here.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

coding challenge - codecaddy multiline

Post by blueznl »

so, a little coding challenge... see here why... yeah, wanna let you do the work :-)

viewtopic.php?t=18133&start=15

the challenge is:

- create some routine that turns 'multiline' purebasic code into single line
- purebasic code, using purebasic only (no asm)
- each line is considered part of a multiline if it ends on [space][underscore], OR
- each line may have a comment after a [space][underscore][space] sequence
- after processing the total number of lines should be the same
- your code may strip the comments
- your code does not need to handle colon's (but it may)
- your code must accept single and double parenthesis ' and "

for bonus points you're allowed to make the 'comments allowed rule' (number 4 above) optional, ie. add a flag to do so or not

who writes the nicest / fastest routine?

and the price? euh... my gratefullness? your name mentioned in codecaddy? or just a general feeling of being good? :-)

example:

Code: Select all

Debug 2+2+ _     ; this is the first line
      2          ; and this is the second
should be turned into

Code: Select all

Debug 2+2+2

example:

Code: Select all

OpenWindow( #1,10,10, 100,100, _     ; line 1
            #PB_Window_SystemMenu, _ ; line 2
            "test")                  ; line 3 contains the title 'test'
should be turned into:

Code: Select all

OpenWindow( #1,10,10,100,100, #PB_Window_SystemMenu, "test")


(added)

here's a file to process (just copy it and save it, then use your code to process it)

Code: Select all

Debug '_' + _ 
      '_'                               ; this is not as easy
Debug '"' + _                           ; as it looks
      'a' 
Debug "'" + "a" + "'"                   ; ah, the joys of coding                                 
Debug Chr('_') _
                                        ; can make life so sweet
Debug "_ is the same as " _
      + Chr('_')
a.l = 1 + _                             ; multiline ahoy
      2 + _
      'b' + _
      Asc("c")         
;
w_main_nr = OpenWindow(#PB_Any, _
            10,10, _
            100,100, _
            #PB_Window_SystemMenu, _ 
            "Test")
Repeat
  event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow
End
Last edited by blueznl on Fri Dec 09, 2005 10:38 pm, edited 2 times in total.
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: coding challenge - codecaddy multiline

Post by PB »

Here's the code I wrote years ago to do it, but doesn't take comments at the
end of lines into account... should be easy enough to modify it though. It
works exactly the same way as Visual Basic does it (which also doesn't
take comments at end of lines into account):

Code: Select all

; Source code line continuation code example by PB.
; Any line ending with " _" carries on to the next line.

; An example of the syntax:

a$="This will comp _
ile into one sing _
le line of code"

o$="old.pb" : n$="new.pb"
;
If ReadFile(0,o$)
  CreateFile(1,n$)
  Repeat
    UseFile(0)
    a$=ReadString()
    While Right(a$,2)=" _"
      l$+Left(a$,Len(a$)-2)
      a$=LTrim(ReadString()) ; LTrim in case continued line was indented.
    Wend
    UseFile(1)
    If l$<>""
      WriteStringN(l$+a$)
      l$=""
    Else
      WriteStringN(a$)
    EndIf
  Until Eof(0)<>0
  CloseFile(0)
  CloseFile(1)
EndIf
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

There are no comments in this one either. It does lines which ends with whitespace after " _" too, unlike PB's version. It's also quite a bit faster. It also keeps the correct number of lines in the file so that error reports on subsequent lines will not come out gonzo (this too unlike PB's version).

Edit: NEVER MIND WAIT A BIT I FORGOT STRINGS! :oops: :oops: :oops:

Code: Select all

Procedure Apple()
ReadFile(0, "in.txt")
Mem = AllocateMemory(Lof()+10)
Ptr = 0
Lin = 0

While Eof(0) = 0
  Lin = 0
  s.s = ReadString()
  For i=0 To Len(s)-1
    If PeekB(@s+i) = ' '
      If PeekB(@s+i+1) = '_'
        s = RTrim(s)
        s = Left(s, Len(s)-2)
        s + Trim(ReadString())
        Lin + 1
      EndIf
    EndIf
  Next
  PokeS(Mem+Ptr, s.s)
  Ptr + Len(s)
  Repeat
    PokeS(Mem+Ptr, #CRLF$)
    Ptr + 2
    Lin - 1
  Until Lin = -1
Wend
CloseFile(0)
CreateFile(0, "out.txt")
WriteData(Mem, Ptr)
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> It does lines which ends with whitespace after " _" too, unlike PB's version

So, just change my line of code from a$=ReadString() to a$=RTrim(ReadString()) ;)

> It's also quite a bit faster

Yep, because it does all the work in memory instead of dual file-access.
As I said, it was written years ago, just as a proof-of-concept. It wasn't
meant to be a final release or anything. :)

> It also keeps the correct number of lines in the file so that error reports
> on subsequent lines will not come out gonzo (this too unlike PB's version)

The concept of mine, as you can see, was to recreate the source, thus any
line numbering issues are totally irrelevant and not an issue. ;)
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

But yours actually WORKS and mine doesn't...
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

I just tried yours and it seems fine?
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

It messes up with _'s inside strings.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

Ah, I see.

BTW, I just tried Visual Basic and note that it doesn't allow multi-line strings
using space+underscore either; the following VB code gives a syntax error
for the definition of a$, but the Debug.Print line works as expected:

Code: Select all

Private Sub Command1_Click()

    a$="hello _
    there"

    Debug.Print _
    a$

End Sub
Also, regarding the issue of the compiler reporting errors on "the wrong
line" -- is this really an issue? Both Visual Basic and PureBasic don't
actually use line numbers... all that matters is the incorrect line gets
highlighted with the error...
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

yes it is, it should mark the right line

regarding long 'strings' as in

Code: Select all

a.s = "dit is een _
test"
it's a bit of a choice, either allow comments behind the _ or allow overlong strings, i prefer comments personally
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

my attempt

uncomment the debug's to see it's output, this one does comments, and makes no mistakes on _ in strings

Code: Select all

Dim source.s(100)
ReadFile(1,"challenge.pb")
n = 0
While Eof(1) = 0
  source.s(n) = ReadString()
  n = n+1
Wend
CloseFile(1)

t1 = GetTickCount_()
For nnn = 1 To 10000
  
  y.s = ""
  For nn = 0 To n-1
    x.s = source.s(nn)
    ;
    x_p = @x
    l = Len(x)                               ; length of string
    t = 0                                    ; test flag, 1 is normal line, 2 is multiline
    p = 0                                    ; counter / pointer
    ;
    If l < 3 Or FindString(x.s," _",1) = 0   ; findstring is faster than my code
      t = 1
    Else
      b = PeekB(x_p+p)
      Repeat
        If b = 34                            ; double quote char
          Repeat                             ; repeat until another one is hit
            p = p+1
            b = PeekB(x_p+p)
          Until b = 34 Or p = l-2
          p = p+1
          b = PeekB(x_p+p)
        ElseIf b = 39                        ; single quote char
          Repeat                             ; repeat until another one is hit
            p = p+1
            b = PeekB(x_p+p)
          Until b = 39 Or p = l-2
          p = p+1
          b = PeekB(x_p+p)
        ElseIf b = ' '                       ; ah a space
          Repeat
            p = p+1
            b = PeekB(x_p+p)
          Until b <> ' ' Or p = l-1          ; keep on going until it's no longer a space
          If b ='_'
            If p = l-1
              t = 2                          ; we're on an eol with a [space][underscore]
              p = p-1                        ; adjust pointer to spot before [underscore]
            Else
              p = p+1
              b = PeekB(x_p+p)
              If b = ' '
                t = 3                        ; we just passed a [space][underscore][space]
                p = p-2                      ; adjust pointer to spot before [underscore]
              EndIf
            EndIf
          EndIf
        ElseIf b = ';' Or b = ':'
          t = 1
        ElseIf p < l-1
          p = p+1
          b = PeekB(x_p+p)
        Else
          t = 1
        EndIf
      Until t <> 0
    EndIf
    ;
    If t=1
      If skiplines = 0
        ; Debug x.s
      Else
        ; Debug y.s+" "+Trim(x.s)
        While skiplines > 0
          ; Debug "; _"
          skiplines = skiplines -1
        Wend
        y.s = ""
      EndIf
    ElseIf skiplines = 0
      y.s = RTrim(Left(x.s,p))
      skiplines = skiplines+1
    Else
      y.s = y.s+" "+Trim(Left(x.s,p))
      skiplines = skiplines+1
    EndIf
  Next nn
  
Next nnn
t2 = GetTickCount_()-t1
Debug t2
End
i used this test file:

Code: Select all

Debug '_' + _ 
      '_'                               ; this is not as easy
Debug '"' + _                           ; as it looks
      'a' 
Debug "'" + "a" + "'"                   ; ah, the joys of coding                                 
Debug Chr('_') _
                                        ; can make life so sweet
Debug "_ is the same as " _
      + Chr('_')
a.l = 1 + _                             ; multiline ahoy
      2 + _
      'b' + _
      Asc("c")         

Procedure _test(a.l)                    ; hahaha, you thought this would be easy huh?
EndProcedure

Procedure test2(a.l)                    ; for example this '''""" _ _ may cause you problems _
EndProcedure

w_main_nr = OpenWindow(#PB_Any, _
            10,10, _
            100,100, _
            #PB_Window_SystemMenu, _ 
            "Test")
Repeat
  event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow
End
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Konne
Enthusiast
Enthusiast
Posts: 434
Joined: Thu May 12, 2005 9:15 pm

Post by Konne »

Thats my little Code!

Code: Select all

Procedure MakeValidPB(LoadFile.s,SaveFile.s)

  ReadFile(1,LoadFile.s)
  *Buffer=AllocateMemory(Lof())
  *Bufferoffset=*Buffer
  
  Repeat
    Wo+1
    String.s=ReadString()    
    Len=Len(String.s)-1
      
    Line=-1
    DLine=-1
    CommentAktiv=0
    
    For i = 0 To Len
      Select PeekS(@String.s+i,1)
        Case Chr(34)
          If Line=-1
            DLine*-1
          EndIf          
          
        Case "'"
          If DLine=-1
            Line*-1
          EndIf          
                    
        Case ";"
          If DLine=-1 And Line=-1   
            NoComment.s=RTrim(PeekS(@String.s,i))
            
            If PeekS(@NoComment.s+Len(NoComment.s)-1,1)="_"
              String.s=NoComment.s
            Else  
              CommentAktiv=1
            EndIf  
          EndIf 
      EndSelect
    Next
   
    
   
    If BreakAktiv=1;PeekS(*Bufferoffset-3,1)="_" And NoBreak=0       
      String.s=Trim(String.s)
      PokeS(*Bufferoffset-3,String.s+#CRLF$)
      *Bufferoffset+Len(String.s)-1      
    Else
      String.s=RTrim(String.s)
      PokeS(*Bufferoffset,String.s+#CRLF$)
      *Bufferoffset+Len(String.s)+2
    EndIf    
    
     ;Debug "Line "+Str(Wo)+" hat Commets "+Str(CommentAktiv)+" und Endet auf "+PeekS(*Bufferoffset-3,1)
    
    If CommentAktiv=0 And PeekS(*Bufferoffset-3,1)="_"
      BreakAktiv=1
    Else
      BreakAktiv=0  
    EndIf
    
  Until Eof(1)<>0
  
  CloseFile(1)
  CreateFile(3,SaveFile.s)
  WriteData(*Buffer,*Bufferoffset-*Buffer)
  CloseFile(3)
  FreeMemory(*Buffer)
EndProcedure

Start=ElapsedMilliseconds()
MakeValidPB("challenge.pb","Whatever.pb")
MessageRequester("Time","The transformation took "+Str(ElapsedMilliseconds()-Start)+" millisecondes.")
Apart from that Mrs Lincoln, how was the show?
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

interesting, konne, we use a very different approach :-)

i did a compare, and we do create binairy identical files (good stuff) but i'm afraid mine is a little faster :-) tried in running it 100 times on a file of 4000 lines with roughly a 100 'continuous' lines

result on my amd64: your code approx 17000 msec mine approx 14000 msec

i'm afraid, however, that both our routines may not be fast enough, as they would slow down the compilation process a little... it's noticable on my amd64, perhaps using a fastfile approach may help a little...

Code: Select all

Procedure MakeValidPB1(LoadFile.s,SaveFile.s)
  
  ReadFile(1,LoadFile.s)
  *Buffer=AllocateMemory(Lof())
  *Bufferoffset=*Buffer
  
  Repeat
    Wo+1
    String.s=ReadString()
    Len=Len(String.s)-1
    
    Line=-1
    DLine=-1
    CommentAktiv=0
    
    For i = 0 To Len
      Select PeekS(@String.s+i,1)
      Case Chr(34)
        If Line=-1
          DLine*-1
        EndIf
        
      Case "'"
        If DLine=-1
          Line*-1
        EndIf
        
      Case ";"
        If DLine=-1 And Line=-1
          NoComment.s=RTrim(PeekS(@String.s,i))
          
          If PeekS(@NoComment.s+Len(NoComment.s)-1,1)="_"
            String.s=NoComment.s
          Else
            CommentAktiv=1
          EndIf
        EndIf
      EndSelect
    Next
    
    
    
    If BreakAktiv=1;PeekS(*Bufferoffset-3,1)="_" And NoBreak=0
      String.s=Trim(String.s)
      PokeS(*Bufferoffset-3,String.s+#CRLF$)
      *Bufferoffset+Len(String.s)-1
    Else
      String.s=RTrim(String.s)
      PokeS(*Bufferoffset,String.s+#CRLF$)
      *Bufferoffset+Len(String.s)+2
    EndIf
    
    ;Debug "Line "+Str(Wo)+" hat Commets "+Str(CommentAktiv)+" und Endet auf "+PeekS(*Bufferoffset-3,1)
    
    If CommentAktiv=0 And PeekS(*Bufferoffset-3,1)="_"
      BreakAktiv=1
    Else
      BreakAktiv=0
    EndIf
    
  Until Eof(1)<>0
  
  CloseFile(1)
  CreateFile(3,SaveFile.s)
  WriteData(*Buffer,*Bufferoffset-*Buffer)
  CloseFile(3)
  FreeMemory(*Buffer)
EndProcedure

Procedure makevalidpb2(loadfile.s,savefile.s)
  ReadFile(1,loadfile.s)
  CreateFile(2,savefile.s)
  ;
  UseFile(1)
  y.s = ""
  While Eof(1) = 0
    x.s = RTrim(ReadString())
    ;
    x_p = @x
    l = Len(x)                               ; length of string
    t = 0                                    ; test flag, 1 is normal line, 2 is multiline
    p = 0                                    ; counter / pointer
    ;
    If l < 3 Or FindString(x.s," _",1) = 0   ; findstring is faster than my code
      t = 1
    Else
      b = PeekB(x_p+p)
      Repeat
        If b = 34                            ; double quote char
          Repeat                             ; repeat until another one is hit
            p = p+1
            b = PeekB(x_p+p)
          Until b = 34 Or p = l-2
          p = p+1
          b = PeekB(x_p+p)
        ElseIf b = 39                        ; single quote char
          Repeat                             ; repeat until another one is hit
            p = p+1
            b = PeekB(x_p+p)
          Until b = 39 Or p = l-2
          p = p+1
          b = PeekB(x_p+p)
        ElseIf b = ' '                       ; ah a space
          Repeat
            p = p+1
            b = PeekB(x_p+p)
          Until b <> ' ' Or p = l-1          ; keep on going until it's no longer a space
          If b ='_'
            If p = l-1
              t = 2                          ; we're on an eol with a [space][underscore]
              p = p-1                        ; adjust pointer to spot before [underscore]
            Else
              p = p+1
              b = PeekB(x_p+p)
              If b = ' '
                t = 3                        ; we just passed a [space][underscore][space]
                p = p-2                      ; adjust pointer to spot before [underscore]
              EndIf
            EndIf
          EndIf
        ElseIf b = ';' Or b = ':'
          t = 1
        ElseIf p < l-1
          p = p+1
          b = PeekB(x_p+p)
        Else
          t = 1
        EndIf
      Until t <> 0
    EndIf
    ;
    If t=1
      If skiplines = 0
        UseFile(2)
        WriteString(x.s+#CRLF$)
        UseFile(1)
      Else
        y.s = y.s+" "+Trim(x.s)+#CRLF$
        While skiplines > 0
          ; y.s = y.s+"; _"+#CRLF$
          skiplines = skiplines -1
        Wend
        UseFile(2)
        WriteString(y.s)
        UseFile(1)
        y.s = ""
      EndIf
    ElseIf skiplines = 0
      y.s = RTrim(Left(x.s,p))
      skiplines = skiplines+1
    Else
      y.s = y.s+" "+Trim(Left(x.s,p))
      skiplines = skiplines+1
    EndIf
  Wend
  If y.s <> ""
    UseFile(2)
    WriteString(y.s+#CRLF$)
  EndIf
  CloseFile(1)
  CloseFile(2)
EndProcedure


Start=ElapsedMilliseconds()
For n = 1 To 100
  MakeValidPB2("challenge2.pb","answer2.pb")
Next n
MessageRequester("Time","Blueznl's transformation took "+Str(ElapsedMilliseconds()-Start)+" millisecondes.")

Start=ElapsedMilliseconds()
For n = 1 To 100
  MakeValidPB1("challenge2.pb","answer1.pb")
Next n
MessageRequester("Time","The transformation took "+Str(ElapsedMilliseconds()-Start)+" millisecondes.")
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Konne
Enthusiast
Enthusiast
Posts: 434
Joined: Thu May 12, 2005 9:15 pm

Post by Konne »

You're right, yours is a little faster. :wink:
But I think that this doesn't matter because the main Fact why the Procedures are "Slow" is because of the File commands, which wouldn't be nessecary if the file would be parsed by the Compiler.

Offcause I tryed to make my Code faster, and replaced the String Ifs with Byte Ifs (like in your Code), but it wasn't much faster that before :D
Apart from that Mrs Lincoln, how was the show?
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

well i put it into codecaddy and it works, speed was not as bad as i feared, though that is on a FAST machine, amd64-3000, haven't checked it yet on slower machines...
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> this one does comments, and makes no mistakes on _ in strings

Strings don't need to be parsed anyway. The whole concept is that any line
ENDING WITH space+underscore gets continued, so all you need to do is
check Right(line$,2) and go from there. All this char-by-char parsing is just
doing obsolete work. :lol:
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Post Reply