My problem is I am trying to add a conditional if-else statement.
The whole program works fine with the original code, but the code breaks when I add it.
My first question is why is it breaking?
My second is how can I add the conditional without breaking it?
Orignal Code
static PyObject*
Aligner_gotoh_local_score_compare(Aligner* self,
const int* sA, Py_ssize_t nA,
const int* sB, Py_ssize_t nB)
{
const double match = self->match;
const double mismatch = self->mismatch;
const double mismatch2 = self->mismatch2;
const double mismatch3 = self->mismatch3;
const int wildcard = self->wildcard;
GOTOH_LOCAL_SCORE(COMPARE_SCORE);
}
Changed Code
static PyObject*
Aligner_gotoh_local_score_compare(Aligner* self,
const int* sA, Py_ssize_t nA,
const int* sB, Py_ssize_t nB)
{
const double match = self->match;
const double mismatch = self->mismatch;
const double mismatch2 = self->mismatch2;
const double mismatch3 = self->mismatch3;
const int wildcard = self->wildcard;
if (mismatch2 == 0)
{
GOTOH_LOCAL_SCORE(COMPARE_SCORE);
}
else
{
GOTOH_LOCAL_SCORE(COMPARE_MULTI_SCORES);
}
}
Error messages
Bio/Align/_aligners.c: In function ‘Aligner_gotoh_local_score_compare’:
Bio/Align/_aligners.c:4937:1: error: duplicate label ‘exit’
4937 | exit: \
| ^~~~
Bio/Align/_aligners.c:6298:9: note: in expansion of macro ‘GOTOH_LOCAL_SCORE’
6298 | GOTOH_LOCAL_SCORE(COMPARE_MULTI_SCORES);
| ^~~~~~~~~~~~~~~~~
Bio/Align/_aligners.c:4937:1: note: previous definition of ‘exit’ was here
4937 | exit: \
| ^~~~
Function where code breaks
#define GOTOH_LOCAL_SCORE(align_score) \
int i; \
int j; \
int kA; \
int kB; \
const double gap_open_A = self->target_internal_open_gap_score; \
const double gap_open_B = self->query_internal_open_gap_score; \
const double gap_extend_A = self->target_internal_extend_gap_score; \
const double gap_extend_B = self->query_internal_extend_gap_score; \
double* M_row = NULL; \
double* Ix_row = NULL; \
double* Iy_row = NULL; \
double score; \
double temp; \
double M_temp; \
double Ix_temp; \
double Iy_temp; \
double maximum = 0.0; \
\
/* Gotoh algorithm with three states */ \
M_row = PyMem_Malloc((nB 1)*sizeof(double)); \
if (!M_row) goto exit; \
Ix_row = PyMem_Malloc((nB 1)*sizeof(double)); \
if (!Ix_row) goto exit; \
Iy_row = PyMem_Malloc((nB 1)*sizeof(double)); \
if (!Iy_row) goto exit; \
\
/* The top row of the score matrix is a special case, \
* as there are no previously aligned characters. \
*/ \
M_row[0] = 0; \
Ix_row[0] = -DBL_MAX; \
Iy_row[0] = -DBL_MAX; \
for (j = 1; j <= nB; j ) { \
M_row[j] = -DBL_MAX; \
Ix_row[j] = -DBL_MAX; \
Iy_row[j] = 0; \
} \
for (i = 1; i < nA; i ) { \
M_temp = M_row[0]; \
Ix_temp = Ix_row[0]; \
Iy_temp = Iy_row[0]; \
M_row[0] = -DBL_MAX; \
Ix_row[0] = 0; \
Iy_row[0] = -DBL_MAX; \
kA = sA[i-1]; \
for (j = 1; j < nB; j ) { \
kB = sB[j-1]; \
SELECT_SCORE_GOTOH_LOCAL_ALIGN(M_temp, \
Ix_temp, \
Iy_temp, \
(align_score)); \
M_temp = M_row[j]; \
M_row[j] = score; \
SELECT_SCORE_LOCAL3(M_temp gap_open_B, \
Ix_row[j] gap_extend_B, \
Iy_row[j] gap_open_B); \
Ix_temp = Ix_row[j]; \
Ix_row[j] = score; \
SELECT_SCORE_LOCAL3(M_row[j-1] gap_open_A, \
Ix_row[j-1] gap_open_A, \
Iy_row[j-1] gap_extend_A); \
Iy_temp = Iy_row[j]; \
Iy_row[j] = score; \
} \
kB = sB[nB-1]; \
Ix_row[nB] = 0; \
Iy_row[nB] = 0; \
SELECT_SCORE_GOTOH_LOCAL_ALIGN(M_temp, \
Ix_temp, \
Iy_temp, \
(align_score)); \
M_temp = M_row[nB]; \
M_row[nB] = score; \
} \
M_temp = M_row[0]; \
Ix_temp = Ix_row[0]; \
Iy_temp = Iy_row[0]; \
M_row[0] = -DBL_MAX; \
Ix_row[0] = 0; \
Iy_row[0] = -DBL_MAX; \
kA = sA[nA-1]; \
for (j = 1; j < nB; j ) { \
kB = sB[j-1]; \
SELECT_SCORE_GOTOH_LOCAL_ALIGN(M_temp, \
Ix_temp, \
Iy_temp, \
(align_score)); \
M_temp = M_row[j]; \
M_row[j] = score; \
Ix_temp = Ix_row[j]; \
Iy_temp = Iy_row[j]; \
Ix_row[j] = 0; \
Iy_row[j] = 0; \
} \
kB = sB[nB-1]; \
SELECT_SCORE_GOTOH_LOCAL_ALIGN(M_temp, \
Ix_temp, \
Iy_temp, \
(align_score)); \
PyMem_Free(M_row); \
PyMem_Free(Ix_row); \
PyMem_Free(Iy_row); \
return PyFloat_FromDouble(maximum); \
exit: \ // Breaks here <<<<<<<
if (M_row) PyMem_Free(M_row); \
if (Ix_row) PyMem_Free(Ix_row); \
if (Iy_row) PyMem_Free(Iy_row); \
return PyErr_NoMemory(); \
Images for more context:
Original code
Changed code
Errors
Where code breaks
CodePudding user response:
There is nothing magic going on here, you need to understand what macros do.
when you do this
if (mismatch2 == 0)
{
GOTOH_LOCAL_SCORE(COMPARE_SCORE);
}
else
{
GOTOH_LOCAL_SCORE(COMPARE_MULTI_SCORES);
}
the line GOTOH_LOCAL_SCORE(COMPARE_SCORE); is replaced by
int i; \
int j; \
int kA; \
int kB; \
....
.....
PyMem_Free(M_row); \
PyMem_Free(Ix_row); \
PyMem_Free(Iy_row); \
return PyFloat_FromDouble(maximum); \
exit: \ // Breaks here <<<<<<<
if (M_row) PyMem_Free(M_row); \
if (Ix_row) PyMem_Free(Ix_row); \
if (Iy_row) PyMem_Free(Iy_row); \
return PyErr_NoMemory(); \
then GOTOH_LOCAL_SCORE(COMPARE_MULTI_SCORES); is also replaced by
int i; \
int j; \
int kA; \
int kB; \
....
.....
PyMem_Free(M_row); \
PyMem_Free(Ix_row); \
PyMem_Free(Iy_row); \
return PyFloat_FromDouble(maximum); \
exit: \ // Breaks here <<<<<<<
if (M_row) PyMem_Free(M_row); \
if (Ix_row) PyMem_Free(Ix_row); \
if (Iy_row) PyMem_Free(Iy_row); \
return PyErr_NoMemory(); \
so now you have 2 exit:
labels declared, thats not allowed.
As others have said, just make it a function
CodePudding user response:
As diagnosed in the comments to the question, the definition of the macro GOTOH_LOCAL_SCORE
defines the label exit:
— consequently, you cannot use the macro twice in a single function. That's because ordinary labels must be unique inside a function. However, case
labels and default
labels can be repeated in different switch
statements.
Check where else that macro is used — but if it was just that one function (which seems likely), then … well, it is a ghastly huge macro and shouldn't be a macro.
Intrusive option — split macro into pieces
It might be feasible to split it into three macros:
GOTOH_LOCAL_SCORE_DECLARATIONS
— defining the variables once.GOTOH_LOCAL_SCORE_WITHOUT_EXIT
containing all the material up to but not including theexit:
label, andGOTOH_LOCAL_SCORE_EXIT
containing theexit:
label and following lines.
You can then use the _DECLARATIONS
macro once, the _WITHOUT_EXIT
variant twice and add the _EXIT
variant once. You can define the original macro using these so you don't break anywhere else that it is used.
In outline:
#define GOTOH_LOCAL_SCORE_DECLARATIONS() \
int i; \
int j; \
int kA; \
int kB; \
const double gap_open_A = self->target_internal_open_gap_score; \
const double gap_open_B = self->query_internal_open_gap_score; \
const double gap_extend_A = self->target_internal_extend_gap_score; \
const double gap_extend_B = self->query_internal_extend_gap_score; \
double* M_row = NULL; \
double* Ix_row = NULL; \
double* Iy_row = NULL; \
double score; \
double temp; \
double M_temp; \
double Ix_temp; \
double Iy_temp; \
double maximum = 0.0
#define GOTOH_LOCAL_SCORE_WITHOUT_EXIT(align_score) \
/* Gotoh algorithm with three states */ \
M_row = PyMem_Malloc((nB 1)*sizeof(double)); \
if (!M_row) goto exit; \
Ix_row = PyMem_Malloc((nB 1)*sizeof(double)); \
if (!Ix_row) goto exit; \
Iy_row = PyMem_Malloc((nB 1)*sizeof(double)); \
if (!Iy_row) goto exit; \
\
… \
\
PyMem_Free(M_row); \
PyMem_Free(Ix_row); \
PyMem_Free(Iy_row); \
return PyFloat_FromDouble(maximum); \
#define GOTOH_LOCAL_SCORE_EXIT() \
exit: \
if (M_row) PyMem_Free(M_row); \
if (Ix_row) PyMem_Free(Ix_row); \
if (Iy_row) PyMem_Free(Iy_row); \
return PyErr_NoMemory()
#define GOTOH_LOCAL_SCORE(align_score) \
GOTOH_LOCAL_SCORE_DECLARATIONS(); \
GOTOH_LOCAL_SCORE_WITHOUT_EXIT(align_score); \
GOTOH_LOCAL_SCORE_EXIT();
And then use these macros like this:
static PyObject*
Aligner_gotoh_local_score_compare(Aligner* self,
const int* sA, Py_ssize_t nA,
const int* sB, Py_ssize_t nB)
{
const double match = self->match;
const double mismatch = self->mismatch;
const double mismatch2 = self->mismatch2;
const double mismatch3 = self->mismatch3;
const int wildcard = self->wildcard;
GOTOH_LOCAL_SCORE_DECLARATIONS();
if (mismatch2 == 0)
{
GOTOH_LOCAL_SCORE_WITHOUT_EXIT(COMPARE_SCORE);
}
else
{
GOTOH_LOCAL_SCORE_WITHOUT_EXIT(COMPARE_MULTI_SCORES);
}
GOTOH_LOCAL_SCORE_EXIT();
}
Less intrusive alternative
static PyObject*
Aligner_gotoh_local_score_compare_VariantA(Aligner* self,
const int* sA, Py_ssize_t nA,
const int* sB, Py_ssize_t nB)
{
const double match = self->match;
const double mismatch = self->mismatch;
const double mismatch2 = self->mismatch2;
const double mismatch3 = self->mismatch3;
const int wildcard = self->wildcard;
GOTOH_LOCAL_SCORE(COMPARE_SCORE);
}
static PyObject*
Aligner_gotoh_local_score_compare_VariantB(Aligner* self,
const int* sA, Py_ssize_t nA,
const int* sB, Py_ssize_t nB)
{
const double match = self->match;
const double mismatch = self->mismatch;
const double mismatch2 = self->mismatch2;
const double mismatch3 = self->mismatch3;
const int wildcard = self->wildcard;
GOTOH_LOCAL_SCORE(COMPARE_MULTI_SCORE);
}
static PyObject*
Aligner_gotoh_local_score_compare(Aligner* self,
const int* sA, Py_ssize_t nA,
const int* sB, Py_ssize_t nB)
{
if (self->mismatch2 == 0)
{
return Aligner_gotoh_local_score_compare_VariantA(self, sA, nA, sB, nB);
}
else
{
return Aligner_gotoh_local_score_compare_VariantB(self, sA, nA, sB, nB);
}
}
That leads to some fairly horrendous code duplication, but doesn't require any change to the macro(s) provided by other people.