Go Down

Topic: How can I see expanded macros? (Read 1 time) previous topic - next topic

TheNorm

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
}


Nick Gammon

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:

[font=Courier]/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[/font]

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

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

[font=Courier]-o/var/folders/1l/43x8v10s1v36trvjz3v92m900000gn/T/build7232351857332367125.tmp/sketch_mar30a.cpp.o[/font]

is replaced by -E.

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

[font=Courier]/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[/font]

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

Code: [Select]
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.

TheNorm

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

Nick Gammon

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

Code: [Select]
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.

TheNorm

#4
Mar 30, 2012, 11:48 pm Last Edit: Mar 31, 2012, 12:13 am by TheNorm Reason: 1
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.

Nick Gammon

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:

Code: [Select]
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 () {}

TheNorm

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.


robtillaart

for strings something like this works

Code: [Select]


#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()
{
};
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart


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

Code: [Select]


#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(){
};
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

TheNorm

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

robtillaart

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.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

TheNorm


Go Up