News:

Let's find out together what makes a PIC Tick!

Main Menu

Are Subs allowed inside Procedures

Started by JohnB, Oct 30, 2022, 02:42 PM

Previous topic - Next topic

JohnB

Is it allowed to have a sub routine within a procedure?  See example below:

  proc BuildLogEntryLine(Row as Byte),as String*64
    Dim itemVal  As Byte
        itemValW As SWord
        tempStr AS String*5

    Sub ValAsString:
      Select itemVal
      Case 0
        TempStr = "Off "
      Case 1
        TempStr = "Auto"
      Case 2
        TempStr = "On  "
      endSelect
    endSub

    ItemVal = LogArray[Row,0]
    Result = Str$(Dec,ItemVal)+":"
    itemVal = LogArray[Row,1]
    Result := result + Str$(Dec,ItemVal)
    itemval = LogArray[Row,2]
    ValAsString
    result = result + TempStr +"  "
    itemval = LogArray[Row,3]
    ValAsString
    Result = Result + TempStr
EndProc

On experimenting, it compiles OK but the item TempStr is not shared with the Subroutine and I get an error TempStr not found.  This format may not be supported but if it is should be able to share variable common to its host procedure.


JohnB

Stephen Moss

I guess only Les would be the only person who would know for certain if a Sub in side a procedure (essential another sub) is treated as local code within the Procedure with access to its Local variable of if being a new sub is regarded as a separate entity that cannot access the local variables.

I could only get it to compile as it was if the Procedure was not called in which case it is not included in the compilation, to get it to compile I had to change it to...
  Proc BuildLogEntryLine(Row As Byte), String*64
    Dim itemVal  As Byte
    Dim    itemValW As SWord
    Dim    TempStr As String*5

    Sub ValAsString:
      Select itemVal
      Case 0
        TempStr = "Off "
      Case 1
        TempStr = "Auto"
      Case 2
        TempStr = "On  "
      EndSelect
    EndSub
   
    'itemVal = LogArray[Row,0]
    Result = Str$(Dec,ItemVal)+":"
    'itemVal = LogArray[Row,1]
    Result := Result + Str$(Dec,ItemVal)
    'itemval = LogArray[Row,2]
    ValAsString()
    Result = Result + TempStr +"  "
    'itemval = LogArray[Row,3]
    ValAsString()
    Result = Result + TempStr

EndProc

Removing As from the procedure declare
Adding Dim for itemValW and tempStr
Commenting out all the "itemVal = LogArray[Row,0]", it I don't think it can do two dimensional arrays and
Adding () after ValAsString to correctly call the Subroutine.

Won't you also need a GoTo to jump over the subroutine otherwise it will be executed first and with no jump to it when it exits it will return to execute the line of code follow that which called the Procedure?

I personally would have though that from a programming standpoint it would generally be a bad idea write the code for one Sub within another. If called from elsewhere then you are essential jumping into the middle of another subroutine, if not then why place it inside the Procedure and not externally as a separate Proceedure, passing itemVal to it and getting TempStr back?

JohnB

#2
Yes, I was still thinking Delphi when I declared the vars.  I was just submitting an update when you responded.

This is my whole routine:
  proc WriteLogLine(Row as Byte), String*64
    Dim itemVal  As Byte
    Dim itemValW As SWord
    Dim tempStr  AS String*5

    Sub ValAsString
      Select ItemVal '
        Case 0 '
          tempStr = "Off " '
        Case 1  '
          TempStr = "On  " '
        Case 2
          TempStr = "Auto" '
      endselect
    endSub

    ItemVal = Read_MultiByteArray LogArray,[Row,0]
    Result  = Str$(Dec,ItemVal)+":"
    itemVal = Read_MultiByteArray LogArray,[Row,1]
    Result  = result + Str$(Dec ItemVal)
    itemval = Read_MultiByteArray LogArray,[Row,2]
    ValAsString
    result  = result + TempStr + "  "
    itemval = Read_MultiByteArray LogArray,[Row,3]
    ValAsString
    Result  = Result + TempStr + "  "
    itemval = Read_MultiByteArray LogArray,[Row,4]
    ValAsString
    Result  = Result + TempStr + "  "
    itemval = Read_MultiByteArray LogArray,[Row,5]
    Result  = Result + TempStr +  "  "
    itemvalW.HighByte = Read_MultiByteArray LogArray,[Row,6]
    itemvalW.LowByte  = Read_MultiByteArray LogArray,[Row,7]
    Result  = Result + Str$(Dec itemVAlW)
    itemvalW.HighByte = Read_MultiByteArray LogArray,[Row,8]
    itemvalW.LowByte  = Read_MultiByteArray LogArray,[Row,9]
    Result  = Result + Str$(Dec itemVAlW)
    itemvalW.HighByte = Read_MultiByteArray LogArray,[Row,10]
    itemvalW.LowByte  = Read_MultiByteArray LogArray,[Row,11]
    Result  = Result + Str$(Dec itemVAlW)
    TempStr ="a"+Str$(dec row+1)
    HMI_SendString(TempStr, Result)
EndProc

This as far as I can see compiles but it seems I cannot call it from another procedure:

  Proc SendLogToHMI(PageNum AS byte)
    Dim Idx As Byte
    Dim Idy AS byte

    for idx = 0 to 12
    idy = Idx+PageNum
      WriteLogLine(Idy)
    next

>Error[113]  D:\DOCUMENTS\PDS\USER\POOLCONTROLLER\A.S 5652 : Symbol not previously defined (WRITELOGLINEVALASSTRING)
>Error[113]  D:\DOCUMENTS\PDS\USER\POOLCONTROLLER\A.S 5687 : Symbol not previously defined (WRITELOGLINEVALASSTRING)
>Error[113]  D:\DOCUMENTS\PDS\USER\POOLCONTROLLER\A.S 5723 : Symbol not previously defined (WRITELOGLINEVALASSTRING)
>ASSEMBLER ERRORS. HEX file not Created

Just for clarification the sub will only ever be called by this procedure.
I am using Les's MultiByteArray macros which enable a two dimension array to be created.
JohnB

Dompie

According to the manual: "Calling a sub only requires the name, and a pair of parenthesis after it."
So Stephen his remark:
QuoteAdding () after ValAsString to correctly call the Subroutine.
is perhaps a solution.

Johan

top204

#4
Once inside a Sub-EndSub, it is not inside a procedure, as far as the compiler is concerned, so it will not recognise its local variables or labels.

I will add an error message if the compiler detects a Sub-EndSub within a procedure's block.

You can always use a standard subroutine within a procedure using the Gosub command, and I have used that a few times in programs to make the subroutine only accessible to that particular procedure, and only created when that particular procedure is used in a program, and use its local variables etc...

For example:

Proc Tester()
    Dim MyByte As Byte

    For MyByte = 0 to 200
        If MyByte = 100 Then Gosub MySub
    Next
    Gosub MySub
    ExitProc

MySub: 
    If MyByte = cDoSomething Then
        ' Do Something here and return via the procedure's Return command at EndProc
    EndIf
EndProc