I have C programs with decrementing software counters. If for instance I want to blink an led every 2 seconds I can do:
if(!ledT) {
ledT = 200;
// code
// code
// code
}
Because I always do the exact same combination with every counter, I tend to type it one line.
if(!ledT) { ledT = 200;
// code
// code
// code
}
For the entire if-line I'd like to use a macro instead. So the code would look something like:
expired(ledT, 200) {
// code
// code
// code
}
I use something similar in my state machine code for the entry state.
if(runOnce) { runOnce = false;
// code
// code
// code
Desired syntax:
entryState {
// code
// code
// code
.
#define entryState if(runOnce) { runOnce = false; // this ofcourse cannot work But something like this is what I want.
I've made several attempts but I got nowhere. The problem is that the {
is somewhere in the middle of the macro and I want to type a {
behind the macro because as we all know, no code editor can live with an unequal number of {
and }
.
expired(ledT, 200); // expired is macro, not function
// code
// code
// code
}
So this is out of the question.
Whilst reading about macros, I've read something interesting about using: do ... while(0). This 'trick' abuses the compiler's optimization feature to create a certain macro, which would otherwise be impossible.
sheds some light about this manner.
Is there a way to use some kind of 'macro trick' to achieve what I want?
So again, that is transforming:
// this
if(runOnce) {
runOnce = false;
// code
// code
// code
// into this
entryState {
// code
// code
// code
// and this:
if(!someTimer) {
someTimer = someInterval;
// code
// code
// code
// must be transformed into:
timeExpired(someTimer, someInterval) {
// code
// code
// code
And an answer like "No, it simply cannot be done" will also be accepted (providing you know what you are talking about)
EDIT: I need to add an addition because not everybody seems to know what I want, the last given answer is not even aimed at the specific problem at hand. Somehow toggling IO suddenly became important? Therfor I altered my code examples to better illustrate what the problem is.
EDIT2: I agree that the the timeExpired macro does not improve readability at all
To show that some macros can improve readabilty I'll give a snippet of a state and a state machine. This is how a generated state looks like in my code:
State(stateName) {
entryState {
// one time only stuff
}
onState {
// continous stuff
exitFlag = true; // setting this, exits the state
}
exitState {
// one time only stuff upon exit
return true;
}
}
Currently in place with these macros:
#define State(x) static bool x##F(void)
#define entryState if(runOnce)
#define onState runOnce = false;
#define exitState if(!exitFlag) return false; else
I think I should I should exchange return true;
in the states by EXIT
or something prittier.
And the state machine which calls these States looks like:
#undef State
#define State(x) break; case x: if(x##F())
extern bit weatherStates(void) {
if(enabled) switch(state){
default: case weatherStatesIDLE: return true;
State(morning) {
if(random(0,1)) nextState(afternoon, 0);
else nextState(rain, 0); }
State(afternoon) {
nextState(evening, 0); }
State(evening) {
if(random(0,1)) nextState(night, 0);
else nextState(thunder, 0); }
State(night) {
nextState(morning, 0); }
State(rain) {
nextState(evening, 0); }
State(thunder) {
nextState(morning, 0); }
break; }
else if(!weatherStatesT) enabled = true;
return false; }
#undef State
The only thing which is not generated are the 'if' and 'else' before the 'nextState()' functions. These 'flow conditions' need filling in.
If a user is provided with a small example or an explanation, he should have no difficulty at all with filling in the states. He should also be able to add states manually.
I'd even like to exchange this by macros:
extern bit weatherStates(void) {
if(enabled) switch(state){
default: case weatherStatesIDLE: return true;
and
break;} }
else if(!weatherStatesT) enabled = true;
return false;}
Why would I do this? To hide irrelevant information out of your display. To remove alot of tabs in the state machine. To increase overal readability by using a simple syntax. Like with 3rd library functions you need to know how to use the code rather to know how the function does the trick.
You don't need to know, how a state signals that it is ready. It is more important to know that the function in question is used as a state function than to know that it returns a bit variable.
Also I test macros before using. So I don't provide somebody with state machines that may show strange behavior.
DISCLAIMER: I don't recommend using this solution.
I had a go at trying to make this into macro's. It is indeed possible but if it's faster, that's another question. As you make a new variable each time you call the macro.
#include <stdio.h>
#define entryState(runOnce) int temp_state = runOnce; if (runOnce) runOnce = 0; if (temp_state)
#define timeExpired(someTimer, someInterval) int temp_expired = someTimer; if (!someTimer) someTimer = someInterval; if (!temp_expired)
int main(int argc, const char* argv[]) {
int runOnce = 1;
int someTimer = 0;
int someInterval = 200;
timeExpired(someTimer, someInterval) {
printf("someTimer is Expired\n");
}
printf("someTimer: %i\n\n", someTimer);
entryState(runOnce) {
printf("this is running once\n");
}
printf("runOnce: %i\n", runOnce);
}
Compiling and running:
c:/repo $ gcc test.c -o test
c:/repo $ ./test.exe
someTimer is Expired
someTimer: 200
this is running once
runOnce: 0
I don't have a C51 compiler at hand now, so I let the testing on the 8051 over to you.