How can I see expanded macros?

I'm fooling around with some macros to implement a select operator similar to the one in VB. I'd like to be able to see what the actual output is rather than just a pass/fail test.

Here's what I'm trying to do...

#define selection switch(0){ if(false);
#define condition(str) else if(str)
#define conditionFail else
#define endSelection }

void doGET(String parameter, EthernetClient client){ // must be a file request
parameter.toLowerCase();
if (parameter=="/") parameter = "/index.htm";
int ptr = parameter.lastIndexOf(".");
String ext = parameter.substring(ptr+1);
DEBUG_PRINT("ext:" << ext );
** selection**
** condition (ext == "htm") doHTML(parameter, client);**
** condition (ext == "jpg") doJPG( parameter, client);**
** condition (ext == "txt") doTXT( parameter, client);**
** conditionFail crash(4002, "unknown file extension");**
** endSelection**
}

I'm not sure if this is the easiest way, but this is how I did it.

Get verbose output (checkbox in Preferences, or hold down Shift while hitting Verify under version 0022).

The first line shown (it might wrap) should be your main sketch, in my case I saw this:

/Applications/Arduino_v0022.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/Applications/Arduino_v0022.app/Contents/Resources/Java/hardware/arduino/cores/arduino /var/folders/1l/43x8v10s1v36trvjz3v92m900000gn/T/build7232351857332367125.tmp/sketch_mar30a.cpp -o/var/folders/1l/43x8v10s1v36trvjz3v92m900000gn/T/build7232351857332367125.tmp/sketch_mar30a.cpp.o

Now, replace the -o ... stuff with -E.

In other words, the output file, in my case:

-o/var/folders/1l/43x8v10s1v36trvjz3v92m900000gn/T/build7232351857332367125.tmp/sketch_mar30a.cpp.o

is replaced by -E.

This outputs the preprocessor output to stdout. You might want to send that to a file, eg.

/Applications/Arduino_v0022.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I/Applications/Arduino_v0022.app/Contents/Resources/Java/hardware/arduino/cores/arduino /var/folders/1l/43x8v10s1v36trvjz3v92m900000gn/T/build7232351857332367125.tmp/sketch_mar30a.cpp -E > ~/nick.txt

Opening that file, near the bottom, I see this:

void doGET(String parameter, EthernetClient client);
void doGET(String parameter, EthernetClient client){
    parameter.toLowerCase();
    if (parameter=="/") parameter = "/index.htm";
    int ptr = parameter.lastIndexOf(".");
    String ext = parameter.substring(ptr+1);
    DEBUG_PRINT("ext:" << ext );
  switch(0){ if(0x0);
      else if(ext == "htm") doHTML(parameter, client);
      else if(ext == "jpg") doJPG( parameter, client);
      else if(ext == "txt") doTXT( parameter, client);
      else crash(4002, "unknown file extension");
    }
}

Having answered your question, I don't know if I would do that personally. I think it just obscures things somewhat. But sometimes it is handy to know what the preprocessor is doing.

Thanks Nick.
I haven't managed to get DOS to accept that string yet, I tried putting it in a bat file but still no joy. I'm running Arduino 1.0 and the output looks a little different. However your copy of the output should be very helpful.
Norm

I don't know what the switch is doing, you don't have any case statements there:

 switch(0){ if(0x0);
      else if(ext == "htm") doHTML(parameter, client);
      else if(ext == "jpg") doJPG( parameter, client);
      else if(ext == "txt") doTXT( parameter, client);
      else crash(4002, "unknown file extension");
    }

Also I advise against using the String class, it can be a memory hog.

The "switch(0){ if(0x0)" was an attempt to get "break" to work for me without having a list of cases. Coming back fresh has shown me that I'm not getting what I want out of this anyway. What I want is a switch/case operator that isn't limited to testing for equality of integers.

"Also I advise against using the String class, it can be a memory hog."
The code needs to be re-entrant and trying to keep track of char *s and their scope was making me crazy.

You can set up a one-shot loop and break out of it like below, but I'm not convinced this is a fantastic idea:

void setup ()
  {
  int a = 42;
  
  do
    {
    if (a == 1) 
       {
       // blah blah 
       break; 
       }
    else if (a == 2)
       {
         
       }
     // and so on ...  
    } while (false);
  
  } // end of setup
void loop () {}

Mmm. If I just use "if"s instead of "else if"s I can get the fall-through effect of a "case" as well as having a "break". I don't quite see how to do "default" at the moment but...

I'd rather use a macro with it's own syntax than an apparently infinite do loop though. Rather than head scratching and figuring out what's going on I'd know right away that I have a specific operator to look up. At least I'm hoping that's how my mind will work after I forget how the code works, in about two days.

for strings something like this works

#define STRSWITCH(STR)      { char _x[16]; strcpy(_x, STR); if (false) {
#define STRCASE(STR)        } else if (strcmp(_x, STR)==0){
#define STRBREAK            ;
#define STRDEFAULT          } else {
#define STRENDSWITCH        }}

void setup()
{
  Serial.begin(9600);
  char x[10];
  strcpy(x, "BEER"); 

  STRSWITCH(x)
    STRCASE ("NOT") 
      Serial.println(1,DEC); 
  STRCASE ("APE") 
    Serial.println(2,DEC);
  STRCASE ("BEER") 
    Serial.println(3,DEC);
  STRCASE ("WINE") 
    Serial.println(4,DEC);
  STRDEFAULT 
    Serial.println("not in the list"); 
  STRENDSWITCH
}

void loop()
{
};

can even be smaller, and yes it uses an hidded variable ...

#define STRSWITCH(STR)      char _x[16]; strcpy(_x, STR); if (false) 
#define STRCASE(STR)        } else if (strcmp(_x, STR)==0){
#define STRDEFAULT          } else {


void setup()
{
  Serial.begin(9600);
  char x[10];
  strcpy(x, "BEER"); 

  STRSWITCH(x)
  {
    STRCASE ("NOT") 
      Serial.println(1,DEC); 
      Serial.println(1,DEC); 
    STRCASE ("APE") 
      Serial.println(2,DEC);
      Serial.println(2,DEC);
    STRCASE ("BEER") 
      Serial.println(3,DEC);
    STRCASE ("WINE") 
      Serial.println(4,DEC);
    STRDEFAULT 
      Serial.println("not in the list");
  }
}
void loop(){
};

Oh, that's nice. I was shooting for a more generic solution not limited to string equalities but that should take care of my current needs very well.

Thanks

if you want a switch that works for all datatypes (including structs etc) than you must rebuild a compiler I guess.

But with the trick above you can (re)make a switch like layout for every datatype, you need a element, a copyfunction and a compare function

#define T_SWITCH(X) element _x; elementCopy(_x, X); if (false)
#define T_CASE(X) } else if (elementCmp(_x, X)==0) {
#define T_DEFAULT } else {

Even making switch for structs like {x,y} is possible this way.

Thanks for all the responses.