Any pre-processor experts? 
Author Message
 Any pre-processor experts?

(Compiler: Clipper 5.2e)

I'm trying to use the pre-processor to improve the readability of my
code, but I've come across a problem with repeating clauses that have
optional parts.  The sample code below is a simplified version of my
code, to illustrate the problem I have encountered.

The problem is that the optional result markers ( <msgN> in my example )
are not kept in sync. with the non-optional ones ( <itemN> ).

Does anyone know of a solution to this? (apart from making all clauses
mandatory).

BTW, I note that the Norton guide states:
  "Repeating clauses cannot be nested.  If you need to nest repeating
   clauses, you probably need an additional #command rule for the
   current command."
Could this be what I need to do, and if so, how?

// == SAMPLE CODE ================================================

// pre-processor rule

#command ADDMENU <title> TO <menu>     ;
     ITEM <item1> [MESSAGE <msg1>]     ;
   [ ITEM <itemN> [MESSAGE <msgN>] ]   ;
                                       ;
   => menuAdd( <menu>, <title>, {      ;
           { <item1>, <msg1> }         ;
        [, { <itemN>, <msgN> }] } )

// First test ---------------------------
//
ADDMENU "Test1" TO menu   ;
   ITEM "I1"              ;
   ITEM "I2"              ;
   ITEM "I3"              ;
   ITEM "I4" MESSAGE "M4"

// pre-processed output:
//
// menuAdd( menu, "Test1", { ;
//    { "I1",      },        ;   // ok
//    { "I2", "M4" },        ;   // WRONG
//    { "I3", "M4" },        ;   // WRONG
//    { "I4", "M4" }       } )   // ok
//
// --------------------------------------

// Second test --------------------------
//
ADDMENU "Test2" TO menu   ;
   ITEM "I1" MESSAGE "M1" ;
   ITEM "I2"              ;
   ITEM "I3" MESSAGE "M3" ;
   ITEM "I4" MESSAGE "M4"

// pre-processed output:
//
// menuAdd( menu, "Test2", { ;
//    { "I1", "M1" },        ;   // ok
//    { "I2", "M3" },        ;   // WRONG
//    { "I3", "M4" },        ;   // WRONG
//    { "I4",      }       } )   // WRONG
//
// --------------------------------------

// == END OF SAMPLE CODE =========================================
--
Douglas Woodrow



Sat, 14 Oct 2000 03:00:00 GMT  
 Any pre-processor experts?


Hi Douglas

[SNIP]

Quote:
> (Compiler: Clipper 5.2e)

)> // == SAMPLE CODE ================================================

Quote:

> // pre-processor rule

> #command ADDMENU <title> TO <menu>     ;
>      ITEM <item1> [MESSAGE <msg1>]     ;
>    [ ITEM <itemN> [MESSAGE <msgN>] ]   ;
>                                        ;
>    => menuAdd( <menu>, <title>, {      ;
>            { <item1>, <msg1> }         ;
>         [, { <itemN>, <msgN> }] } )

> // First test ---------------------------
> //
> ADDMENU "Test1" TO menu   ;
>    ITEM "I1"              ;
>    ITEM "I2"              ;
>    ITEM "I3"              ;
>    ITEM "I4" MESSAGE "M4"

> // pre-processed output:
> //
> // menuAdd( menu, "Test1", { ;
> //    { "I1",      },        ;   // ok
> //    { "I2", "M4" },        ;   // WRONG
> //    { "I3", "M4" },        ;   // WRONG
> //    { "I4", "M4" }       } )   // ok
> //
> // --------------------------------------

What about :

#command ADDMENU <title> TO <menu>     ;
     ITEM <item1> [MESSAGE <msg1>]     ;
   [, ITEM <itemN> [MESSAGE <msgN>] ]   ;   // The difference is in the comma
                                       ;
   => menuAdd( <menu>, <title>, {      ;
           { <item1>, <msg1> }         ;
        [, { <itemN>, <msgN> }] } )

ADDMENU "Test1" TO menu   ;
   ITEM "I1" ,              ; // again, the commas
   ITEM "I2" ,             ;
   ITEM "I3" ,             ;
   ITEM "I4" MESSAGE "M4"

It should work.
Ciao

Sebastien




Sun, 15 Oct 2000 03:00:00 GMT  
 Any pre-processor experts?

Quote:

> The problem is that the optional result markers ( <msgN> in my example )
> are not kept in sync. with the non-optional ones ( <itemN> ).

> Does anyone know of a solution to this? (apart from making all clauses
> mandatory).

IIRC this is a problem/bug/feature with the pre-processor. I can remember
running into this a while ago.

Another solution might be to break your menu definition code down a bit. For
example, have the resulting commands look like:

   Create Menu mnuFiles Title "File" On mnuTopBar
   Add Item "~New"  Message "Create a new file" To mnuFiles
   Add Item "~Open"                             To mnuFiles
   Add Item "~Save"                             To mnuFiles

etc. The resulting PPO file might look like:

   // mnuTopBar is defined elsewhere
   mnuFiles := {}; menuAdd( mnuTopBar, "File", mnuFiles )
   menuItemAdd( mnuFiles, "~New", "Create a new file" )
   menuItemAdd( mnuFiles, "~Open" )
   menuItemAdd( mnuFiles, "~Save" )

Obviously, how feasible this is will depend on how easy it is for you to
re-work your underlying menu building/handling code.

--
Take a look in Hagbard's World: |     w3ng - The WWW Norton Guide reader.
http://www.acemake.com/hagbard/ |  ng2html - The NG to HTML converter.
http://www.hagbard.demon.co.uk/ |       eg - Norton Guide reader for Linux.
Free software, including........|   dgscan - DGROUP scanner for Clipper.



Sun, 15 Oct 2000 03:00:00 GMT  
 Any pre-processor experts?


oo.com> wrote

Quote:
>What about :

>#command ADDMENU <title> TO <menu>     ;
>     ITEM <item1> [MESSAGE <msg1>]     ;
>   [, ITEM <itemN> [MESSAGE <msgN>] ]   ;      // The difference is in the
>comma
>                                       ;
>   => menuAdd( <menu>, <title>, {      ;
>           { <item1>, <msg1> }         ;
>        [, { <itemN>, <msgN> }] } )

>It should work.

Thanks for your interest.

It was worth a try, but no, it doesn't work either (it produces exactly
the same output).

Any other suggestions?
--
Douglas Woodrow



Sun, 15 Oct 2000 03:00:00 GMT  
 Any pre-processor experts?


.uk> wrote

Quote:
>Another solution might be to break your menu definition code down a bit. For
>example, have the resulting commands look like:

>   Create Menu mnuFiles Title "File" On mnuTopBar
>   Add Item "~New"  Message "Create a new file" To mnuFiles
>   Add Item "~Open"                             To mnuFiles
>   Add Item "~Save"                             To mnuFiles

>etc. The resulting PPO file might look like:

>   // mnuTopBar is defined elsewhere
>   mnuFiles := {}; menuAdd( mnuTopBar, "File", mnuFiles )
>   menuItemAdd( mnuFiles, "~New", "Create a new file" )
>   menuItemAdd( mnuFiles, "~Open" )
>   menuItemAdd( mnuFiles, "~Save" )

Thankyou for your suggestion.  I was trying to avoid that solution
because I don't want to create array variables for each sub-menu.  The
array passed to menuAdd() is just a temporary one (the relevant
information from it is stored in the main menu array).

I have come up with a workaround using 3 pre-processor rules.  It is not
a very elegant solution because it requires a local variable, _aTmp, to
be declared (unless you're happy to have auto-created private variables
in your code).

For anyone who may be interested, it is as follows:

#command ADDMENU <title> TO <menu> ITEM [<Clauses,...>] ;
      => _aTmp := {}                                    ;
       ; _ADD [<Clauses>]                               ;
       ; menuAdd( <menu>, <title>, _aTmp )              ;
       ; _aTmp := NIL     // release memory

// recursive rule to get each item separately
#command _ADD [<Clauses,...>] ITEM [<moreClauses,...>]  ;
      => _ADD [<Clauses>]                               ;
       ; _ADD [<moreClauses>]

#command _ADD <item> [MESSAGE <msg>]                    ;
      => aAdd( _aTmp, { <item>, <msg> } )

// Example test:
//
ADDMENU "Test" TO menu    ;
   ITEM "I1" MESSAGE "M1" ;
   ITEM "I2"              ;
   ITEM "I3" MESSAGE "M3" ;
   ITEM "I4" MESSAGE "M4"

// pre-processed output:
//
// _aTmp := {}
// aAdd( _aTmp, { "I1", "M1" } )
// aAdd( _aTmp, { "I2",      } )
// aAdd( _aTmp, { "I3", "M3" } )
// aAdd( _aTmp, { "I4", "M4" } )
// menuAdd( menu, "Test", _aTmp )
// _aTmp := NIL

--
Douglas Woodrow



Sun, 15 Oct 2000 03:00:00 GMT  
 Any pre-processor experts?

Quote:

> I have come up with a workaround using 3 pre-processor rules.  It is not a
> very elegant solution because it requires a local variable, _aTmp, to be
> declared (unless you're happy to have auto-created private variables in
> your code).

You could probably get away with not having to declare the local _aTmp. How
about, with your menu code, you do:

  Function mnuHelper( x )
  Static hMenu

     If pcount() == 1
        hMenu := x
     EndIf

  Return( hMenu )

Then, your #command would look like:

----------------------------------------------------------------------------
#command ADDMENU <title> TO <menu> ITEM [<Clauses,...>] ;
      => mnuHelper( {} )                                ;
       ; _ADD [<Clauses>]                               ;
       ; menuAdd( <menu>, <title>, mnuHelper() )        ;
       ; mnuHelper( NIL )   // release memory

// recursive rule to get each item separately
#command _ADD [<Clauses,...>] ITEM [<moreClauses,...>]  ;
      => _ADD [<Clauses>]                               ;
       ; _ADD [<moreClauses>]

#command _ADD <item> [MESSAGE <msg>]                    ;
      => aAdd( mnuHelper(), { <item>, <msg> } )
----------------------------------------------------------------------------

Note, I've not tested this, it is off the top of my head. However, it should
work. With the addition of the above it will make the menu commands "clean"
because the "user" of the commands won't need to declare the temporary local
variable.

BTW, I'd probably give the _ADD command a more unique name (in case it were
ever to clash with something else), but that is just a detail.

Nice workaround.

--
Take a look in Hagbard's World: |     w3ng - The WWW Norton Guide reader.
http://www.acemake.com/hagbard/ |  ng2html - The NG to HTML converter.
http://www.hagbard.demon.co.uk/ |       eg - Norton Guide reader for Linux.
Free software, including........|   dgscan - DGROUP scanner for Clipper.



Mon, 16 Oct 2000 03:00:00 GMT  
 Any pre-processor experts?


.uk> wrote

Quote:
>You could probably get away with not having to declare the local _aTmp. How
>about, with your menu code, you do:

>  Function mnuHelper( x )
>  Static hMenu

>     If pcount() == 1
>        hMenu := x
>     EndIf

>  Return( hMenu )

Brilliant!  Thankyou very much.

Quote:
>Note, I've not tested this, it is off the top of my head.

Seems like a pretty reliable source to me.

Quote:
> However, it should
>work.

Certainly does.  (Good example of the usefulness of the pcount()
function, too)

Quote:
>BTW, I'd probably give the _ADD command a more unique name (in case it were
>ever to clash with something else), but that is just a detail.

Good point - I've changed it to _ADDMNUITEM.

Quote:
>Nice workaround.

Thankyou.  I was quite pleased with it myself, except for the _aTmp
problem.
--
Douglas Woodrow


Mon, 16 Oct 2000 03:00:00 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. Observation : Clipper 5.2e - Pre-processor bug

2. Ann: xBaseScript RC-1 (Script Engine, DOT Environment, and Clipper compaqtible Pre-Processor)

3. Size of Pre Processor Table

4. LF: Pre-Release of an NPBP ANS Forth Word Processor

5. Help: characterize power of C pre-processor

6. Limits of a simple C pre-processor.

7. Difference between FS and Clipper pre-processor?

8. Help with Pl1 Pre Processor Parser (Operation PPPP!)

9. pmpp 0.01 - HTML Pre-Processor

10. Use of REXX as Compiler Pre-processor

11. Rewriting pre-processor for scheme?

12. Scheme Pre-processor

 

 
Powered by phpBB® Forum Software