Basic-Macros in fbc 1.08

Forum for discussion about the documentation project.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Basic-Macros in fbc 1.08

Post by fxm »

coderJeff wrote:We are probably OK on the changelog.txt, these basic-macros are still new to 1.08.0. I can update the changelog to show the sytaxes though.
It all depends if we consider that changelog.txt is:
- only a synthesis of the modifications compared to the previous fbc version,
- or otherwise as a logbook of the working version evolution.

This second definition (my favorite) is more practical to manage the day-to-day updating of the documentation.
That is why I would rather prefer a new line (in changelog.txt) like:
- add optional return arg for FB_ARG_LEFTTOF and FB_ARG_RIGHTTOF
adeyblue
Posts: 299
Joined: Nov 07, 2019 20:08

Re: Basic-Macros in fbc 1.08

Post by adeyblue »

I've been umming and ahhing a bit. I did it all the stuff but it's not far enough for the use case I had in mind.

What I was doing was something like

Code: Select all

#macro PRINT_LAST(args...) 

'' #define LAST_ARG_NUM __FB_UNQUOTE__(__FB_EVAL__(__FB_QUOTE__(__FB_ARG_COUNT__(args) - 1)))
#define LAST_ARG_NUM __FB_ARG_COUNT__(args) - 1

#Print __FB_ARG_EXTRACT__(LAST_ARG_NUM, args)

#endmacro

PRINT_LAST(7, 89.78, "Postman", 0)
As there's no reduction from "4-1" to "3" at any point, nor can I seem to force EVAL to reduce it, arg_extract fails because it's not a single literal number. I know this is exactly how its supposed to work, on tokens rather than values, so it's less of a complaint that it doesn't reduce, and more of a 'Is ARG_EXTRACT still useful enough with this limitation?'

I mean, if you can pass a literal to it you're probably already using a fixed number of args to your macro (or expecting the user to), no? I'll submit it anyway and then depending on what you think you can bin it
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Basic-Macros in fbc 1.08

Post by coderJeff »

This seems to work for me using the code from your post.

Code: Select all

#macro PRINT_LAST(args...)
#define LAST_ARG_NUM __FB_EVAL__(__FB_ARG_COUNT__(args)-1 )
#print __FB_ARG_EXTRACT__(LAST_ARG_NUM, args)
#endmacro
PRINT_LAST(7, 89.78, "Postman", 0)
This is a much better example of how '__FB_EVAL__' can be used. It's hard to show in the wiki example because most examples of `__FB_EVAL__` could only be shown where an expression would be evaluated anyway, which is the reason for the extra quote/unquote stuff in the example.

Any advantage of using one-based instead of zero-based? I was trying to think of a use case where an index of 0 returns nothing. Though should get nothing returned if with -1, so is probably academic.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Basic-Macros in fbc 1.08

Post by fxm »

The shown result for each of the two posts above is not demonstrative to us, because since '__FB_ARG_EXTRACT__' is not defined, then 'LAST_ARG_NUM' is not evaluated in the compiler output message.
Compiler output message for both:
__FB_ARG_EXTRACT__(LAST_ARG_NUM, 7, 89.78, "Postman", 0)

On the other hand, '#print LAST_ARG_NUM, args' by itself is more demonstrative.
Compiler output messages:
4 -1, 7, 89.78, "Postman", 0
3, 7, 89.78, "Postman", 0
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Basic-Macros in fbc 1.08

Post by coderJeff »

'__FB_ARG_EXTRACT__(index, args...)` is merged in now to fbc/master now.
fxm wrote:It all depends if we consider that changelog.txt is:
- only a synthesis of the modifications compared to the previous fbc version,
- or otherwise as a logbook of the working version evolution.
I was thinking of it as a comparison to previous version. I'll keep in mind using like a logbook; I can see how that will be a useful way to communicate changes.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Basic-Macros in fbc 1.08

Post by fxm »

coderJeff wrote:'__FB_ARG_EXTRACT__(index, args...)` is merged in now to fbc/master now.
Documentation updated:
- KeyPgDdfbargextract → fxm [new page created]
- CatPgFullIndex → fxm [added link to __FB_ARG_EXTRACT__]
- CatPgFunctIndex → fxm [added link to __FB_ARG_EXTRACT__]
- CatPgDddefines → fxm [added link to __FB_ARG_EXTRACT__]
- KeyPgDdfbargcount → fxm [added link to __FB_ARG_EXTRACT__]
- KeyPgDdfbargrightof → fxm [added link to __FB_ARG_EXTRACT__]
- KeyPgDdfbargleftof → fxm [added link to __FB_ARG_EXTRACT__]
- KeyPgDdfbeval → fxm [added link to __FB_ARG_EXTRACT__]
- PrintToc → fxm [added link to __FB_ARG_EXTRACT__]
adeyblue
Posts: 299
Joined: Nov 07, 2019 20:08

Re: Basic-Macros in fbc 1.08

Post by adeyblue »

Thanks to most of these new macros, there's now some semblance of a strongly typed generic List/Vector with not entirely wonky usage syntax. The only dodginess is that types in namespaces need to be delimited in , in these macros rather than . since there's no way to split on . in macros to create unique typenames.

Cue the 'that doesn't look like basic' comments :-)
https://github.com/adeyblue/fbc/commit/ ... 703bf90ec9

Code: Select all

#include once "inc/containers/List.bi"
FBCont_DefineListOf(Long)
''FBCont_DefineListOf(MyNamespace, MySecondNamespace, MyType Ptr) '' namespaced types have to declared like this

'' Iterator to generate n sequential numbers
Type SequentialLongGenerator extends FB_IIterator(Long)
Private:
Dim numToGenerate As Long
Dim soFar As Long
Dim firstVal As Long

Public:
    Declare Constructor(ByVal howMany as Long, ByVal startPoint As Long)
    Declare Function Advance() As Boolean Override
    Declare Function Item() ByRef As Long Override
    Declare Sub Reset() Override
End Type

Private Constructor SequentialLongGenerator(ByVal howMany As Long, ByVal startPoint As Long)
    numToGenerate = howMany
    firstVal = startPoint
    Reset()
End Constructor

Private Function SequentialLongGenerator.Advance() As Boolean
    soFar += 1
    Return soFar < (firstVal + numToGenerate)
End Function

Private Function SequentialLongGenerator.Item() ByRef As Long
    Return soFar
End Function

Private Sub SequentialLongGenerator.Reset()
    soFar = firstVal - 1
End Sub

Sub PrintIterator(ByVal pIterator As FB_IIterator(Long) Ptr)
    While pIterator->Advance()
        Print Using "& "; pIterator->Item();
    WEnd
    Print
End Sub

Sub PrintList(list As FB_List(Long), message As String)
    Print message;
    Print Using ", Count: &, Capacity: &"; list.Count; list.Capacity
    Var pIterator = list.GetIterator()
    PrintIterator(pIterator)
    Delete pIterator
End Sub

'' will create 15 numbers starting at 0
Dim slg As SequentialLongGenerator = Type(15, 0)

Print "To add to the list:"
PrintIterator(@slg)
slg.Reset()

'' Create a list using the iterator
Dim myList As FB_List(Long) = @slg

slg.Reset()

PrintList(myList, "Items in the list")

'' remove the item at index 7 (0 based)
myList.RemoveAt(7)
PrintList(myList, "Items after removing 7")

'' Insert another 15 numbers at index 7
myList.Insert(7, @slg)
PrintList(myList, "Items after inserting 15")

myList.RemoveSpan(0, 7)
PrintList(myList, "Items after removing first 7")

Dim testArr(Any) As Long
myList.CopyTo(testArr())

Print Using "TestArr lbound &, testarr ubound &"; LBound(testArr); UBound(testArr)
adeyblue
Posts: 299
Joined: Nov 07, 2019 20:08

Re: Basic-Macros in fbc 1.08

Post by adeyblue »

I'm trundling along with these and the framework seems to be working good, but suprisingly the one I'm having the most problems with isn't a macro, and I can't figure out why it won't compile.

If anybody wants to see if they can figure it out, here's the code, and this illustrates the problem

Code: Select all

F:\Dev-Cpp\Projects\FB\containers\bug>..\fbc -i ..\.. -c bitcontainertest.bas
Containers: Generating-IIteratorBoolean
Containers: Generating-IContainerBoolean

F:\Dev-Cpp\Projects\FB\containers\bug>..\fbc -d REAL_HEADERS -i ..\.. -c bitcontainertest.bas
Containers: Generating-IIteratorBoolean
Containers: Generating-IContainerBoolean

F:\Dev-Cpp\Projects\FB\containers\bug>..\fbc -d REAL_CODE -i ..\.. -c bitcontainertest.bas
Containers: Generating-IIteratorBoolean
Containers: Generating-IContainerBoolean

F:\Dev-Cpp\Projects\FB\containers\bug>..\fbc -d REAL_CODE -d REAL_HEADERS -i ..\.. -c bitcontainertest.bas
Containers: Generating-IIteratorBoolean
Containers: Generating-IContainerBoolean
F:\Dev-Cpp\Projects\FB\containers\bug\BitContainer.bi(272) error 290: Expected '#ENDIF' in 'dim mask As UByte'
bitcontainertest.bas(17) error 290: Expected '#ENDIF' in 'bits.SetAll()'
Essentially:
the full code BitContainer.bi with the real IContainer and IIterator bi doesn't compile
The full BitContainer with the non-macro bi files (the _mock bi's) does compile
Except, the BitContainerStub (which doesn't have any code in its subs) compiles fine with the real headers, as do all the other macro containers I've written so far

The weird thing is that if you move the function order around in the full file, the error is always between lines 260-280, and that's where the -pp output stops dead - so it's a good bet that the compiler thinks its expanding a macro and hitting a roughly 10,000-ish character limit, maybe? It's going to be something dumb like a single extra or missed bracket but I've been looking for it all day and still have no idea what or where
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Basic-Macros in fbc 1.08

Post by coderJeff »

I guessed you meant to have BitContainer.zip in the link. I was able to reproduce the error.

First try through debugging of fbc was a bit of trial and error to see that it is related to lex.bi:LEX_MAXBUFFCHARS which is currently 8192. Changing the value of LEX_MAXBUFFCHARS to +1 will cause the compile error one character later. And arbitrarily doubling it will allow the code to compile.

I'll have to dig more to find a satisfying explanation, or what can be done about it.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Basic-Macros in fbc 1.08

Post by coderJeff »

adeyblue wrote:It's going to be something dumb like a single extra or missed bracket but I've been looking for it all day and still have no idea what or where
It's not your code... A bug (or bugs), somewhere in the compiler

Code: Select all

__FB_UNQUOTE__( __FB_EVAL__( "#define " "X" " 1" ) )
print X
output:
c.bas(1) error 7: Expected ')', expanding: __FB_UNQUOTE__ in '__FB_UNQUOTE__( __FB_EVAL__( "#define " "X" " 1" ) )'

A slightly more complex case based on the bitcontainer headers, where can see an extra token or character is being eaten.

Code: Select all

#define A() __FB_UNQUOTE__(__FB_EVAL__("""print"""))

#macro B(arg)
#if 1
__FB_UNQUOTE__(__FB_EVAL__(""))
#endif
#endmacro

#define C() B(A())

C()

#define D
output:
a.bas(11) warning 44(1): Suffix ignored in 'endif#'
a.bas(11) error 3: Expected End-of-Line, found 'define' in '#define D'

I changed the LEX buffer to 1 byte, to help debug so there's no buffering except for one character. But I didn't find the cause yet.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Basic-Macros in fbc 1.08

Post by coderJeff »

Was bit of long walk, but I got there. Should be fixed in fbc/master now. And bitcontainer with -d REAL_CODE and -d REAL_HEADERS will compile now.

I added an error message for __FB_EVAL__ if does actually have a bad expression that's hopefully not too wonky. Previously, there could be junk after a valid expression and no error message would be thrown. Now it's like:

Code: Select all

__FB_UNQUOTE__( __FB_EVAL__( "#define " "X" 2 ) )
Output:
e.bas(1) error 17: Syntax error, "#define " "X" 2 in '__FB_UNQUOTE__( __FB_EVAL__( "#define " "X" 2 ) )'
In this case, can't mix string literals and numbers so should be an error
adeyblue
Posts: 299
Joined: Nov 07, 2019 20:08

Re: Basic-Macros in fbc 1.08

Post by adeyblue »

You the man, Jeff!

Now to write all the tests and find all the dumb mistakes which I definitely have to take ownership of
adeyblue
Posts: 299
Joined: Nov 07, 2019 20:08

Re: Basic-Macros in fbc 1.08

Post by adeyblue »

Should this code work?
I've put debugging stuff into the containers so that with a define things like out of bounds accesses and similar call Error. As I've discovered trying to run the tests with it set though, catching the errors like below causes the tests (and this code) to crash.

Code: Select all

Sub CallsError(byVal x As Long)
   Error 6 '' something to trigger an error
End Sub

Sub MainSub()
   dim arr(Any) As Long
   On Local Error Goto nextTest
   CallsError(7)
nextTest:
   Print "After error, arr size is " & Str(UBound(arr) + 1) '' crashes before it prints
End Sub

MainSub()
SARG
Posts: 1755
Joined: May 27, 2005 7:15
Location: FRANCE

Re: Basic-Macros in fbc 1.08

Post by SARG »

From documentation about On Error : "the handler must be in the main part of the module." See the example.

In the case reported as arr() is local its address is relative to ebp/rbp depending of each procedure.
The jump form callerror to mainsub doesn't restore the value of ebp/rbp when it was in mainsub --> crash.

Using a shared variable (not on the stack) the message is displayed but I guess with a bigger program an error should arise at a moment.
adeyblue
Posts: 299
Joined: Nov 07, 2019 20:08

Re: Basic-Macros in fbc 1.08

Post by adeyblue »

Yeah, it crashes no matter where the handler is, as long as the Error statement is within a deeper sub/function. Not fixing the stack would do that. So it maybe should work, it's just broken.
Have we considered adding that as a slogan underneath the horse?
Post Reply