Quiero reducir la bifurcación anidada profunda de este código C y me pregunto si hay una herramienta de análisis que pueda hacer una tabla de verdad para las condiciones o si debo analizarla manualmente. Me gustaría hacer que el código sea más legible y menos ramificado. Mi IDE CLion de JetBrains no dice nada sobre cómo realizar dicha refactorización. ¿Se puede automatizar? No intenté usar Lint pero podría intentarlo.
if (ptr + j) {
if (*(ptr + j)[0] == '{') {
keep = true;
}
if (testFn(*(ptr + j))) { /* test for last char */
string[i][j - p] = concat(*pString1, *(ptr + j));
keep = false;
free(*pString1);
goto mylabel;
}
if (keep) {
*pString1 = concat(*pString1, *(ptr + j));
*pString1 = concat(*pString1, " ");
p++;
} else {
b1 = false;
int q = j;
for (e = 0; *(ptr + q + e); e++) { /* step through the string */
b1 = true;
if (*(ptr + e + q)) {
*pString = concat(*pString, *(ptr + e + q));
*pString = concat(*pString, " ");
}
j = e;
}
if (makeArgs(*pString, &argc, (const char ***) &argv, pipe, i, h)) {
write_command(&w, argv, string[w]);
w++;
} else {
if (!b1) { /* no args (?) */
for (int r = 0; argv[r] != NULL; r++) {
string[i][r] = argv[r]; /* is this necessary? */
}
}
}
}
}
Pude reducir la bifurcación condicional manualmente, pero no hice una tabla de verdad. Creo que los análisis de código deberían decir qué ramas son idénticas y cuándo con una tabla de verdad.
La función completa se ve así hoy:
static int runCmd(const char *cmd) {
const char *cp;
pid_t pid;
int status;
struct command structcommand[15];
char **argv = 0;
int argc = 1;
bool pipe = false;
char *string[z][z];
char *pString3[40];
char *pString2[40];
int n = 0;
char **ptr1;
char string1[z];
bool keep = false;
char *pString1[z];
char *pString[z];
*pString1 = "\0";
*pString = "\0";
char *temp = {'\0'};
int w = 0;
bool quote = false;
int rrs[256];
int j = 0;
int i;
int p = 0;
char **ptr;
int count = 0;
char *cmdtmp;
bool b1 = false;
int y = 0;
i = 0;
int h = 0;
char *str;
char *freeme[75][75];
char **dealloc[75];
char **dealloca[75][75];
int acount[128];
nullterminate(string);
int rr = 0;
for (z = 0; z < 128; z++) {
acount[z] = -1;
}
for (int f = 0; f < 75; f++) {
dealloc[f] = NULL;
for (z = 0; z < 75; z++) {
freeme[f][z] = NULL;
}
}
if (cmd) {
for (cp = cmd; *cp; cp++) {
if ((*cp >= 'a') && (*cp <= 'z')) {
continue;
}
if ((*cp >= 'A') && (*cp <= 'Z')) {
continue;
}
if (isDecimal(*cp)) {
continue;
}
if (isBlank(*cp)) {
continue;
}
if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
(*cp == '+') || (*cp == '=') || (*cp == '_') ||
(*cp == ':') || (*cp == ',') || (*cp == '\'') ||
(*cp == '"')) {
continue;
}
}
cmdtmp = strdup(cmd);
ptr1 = str_split(pString3, cmdtmp, '|');
if (strstr(cmd, "|") == NULL) { /* not a pipeline */
makeArgs(cmd, &argc, (const char ***) &argv, pipe, 0, 0);
write_argument(&argc, structcommand, argv, string[0]);
n++;
}
else {
for (i = 0; *(ptr1 + i); i++) { /* loop for each pipeline*/
n++;
/* save number of pipelines */
dealloc[n] = NULL;
int e = 0; /* a counter */
*pString = "\0"; /* should malloc and free this? */
strcpy(string1, *(ptr1 + i));
if ((string1[0] != '\0') &&
!isspace(string1[0])) { /* this is neither the end nor a new argument */ /* BSD bug? check*/
ptr = str_split(pString2, *(&string1), ' '); /* split the string at the arguments */
dealloc[rr] = ptr;
rr++;
h = 0;
for (j = 0; *(ptr + j); j++) { /* step through the arguments */
dealloca[n][n - 1] = NULL;
/* the pipeline is in cmdtmp and the argument/program is in ptr[i] */
if (ptr + j && !quote && strstr(*(ptr + j), "'")) { /* is quote? */
quote = true;
strcpy(temp, *(ptr + j)); /* point where quoted piipelines crash */
if (y < 1) {
y++;
}
}
while (quote) {
if (*(ptr + j) && strstr(*(ptr + j), "'")) { /* end of quote */
quote = false;
if (y < 1) {
string[i][j] = strcpy(temp, *(ptr + j));
}
y = 0;
}
else if (*(ptr + j)) { /* read until end of quote */
string[i][j] = temp;
continue;
} else {
quote = false;
break;
}
}
if (ptr + j) { ;
if (*(ptr + j)[0] == '{') {
keep = true;
}
if (testFn(*(ptr + j))) { /* test for last char */
string[i][j - p] = concat(*pString1, *(ptr + j));
keep = false;
free(*pString1);
continue;//goto mylabel;
}
if (keep) {
str = concat(*pString1, *(ptr + j));
*pString1 = concat(str, " ");
free(str);
p++;
} else {
b1 = false;
int q = j;
freeme[i][0] = *pString;
for (e = 0; *(ptr + q + e); e++) { /* step through the string */
b1 = true;
if (*(ptr + e + q)) {
str = concat(*pString, *(ptr + e + q));
*pString = concat(str, " "); /* how to free() ? */
free(str);
freeme[i][e] = *pString;
}
j = e; /* adjust the counter */
}
if (makeArgs(freeme[i][e - 1], &argc, (const char ***) &argv, pipe, i, h)) {
write_command(&w, argv, string[w]);
w++;
for (int qwe = 0; qwe < argc; qwe++) {
dealloca[n - 1][qwe] = &argv[qwe];
}
acount[n - 1] = argc;
} else {
if (!b1) { /* no args (?) */
for (int r = 0; argv[r] != NULL; r++) {
string[i][r] = argv[r]; /* is this necessary? */
}
}
}
}
}
}
bool boo = false;
dump_argv((const char *) "d", argc, argv, boo);
}
}
}
for (i = 0; i < n; i++) {
structcommand[i].argv = string[i];
for (j = 0; string[i][j] != NULL; j++) {
if (string[i] != NULL) {
}
}
}
free(cmdtmp);
if (ptr1) {
int i;
for (i = 0; *(ptr1 + i); i++) {
free(*(ptr1 + i));
}
printf("\n");
free(ptr1);
}
fflush(NULL);
pid = fork();
if (pid < 0) {
perror("fork failed");
return -1;
}
/* If we are the child process, then go execute the string.*/
if (pid == 0) {
/* spawn(cmd);*/
fork_pipes(n, structcommand);
}
/*
* We are the parent process.
* Wait for the child to complete.
*/
status = 0;
while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
if (pid < 0) {
fprintf(stderr, "Error from waitpid: %s", strerror(errno));
return -1;
}
if (WIFSIGNALED(status)) {
fprintf(stderr, "pid %ld: killed by signal %d\n",
(long) pid, WTERMSIG(status));
return -1;
}
}
for (i = 0; i < n; i++) {
for (j = 0; string[i][j] != NULL; j++) {
if (string[i] != NULL) {
if (string[i][j])
free(string[i][j]);
}
}
}
int z;
for (int f = 0; f < n; f++) {
if (f > 0) {
}
for (z = 0; freeme[f][z]; z++) {
free(freeme[f][z]);
}
}
size_t idx;
for (int f = 0; n > 1 && f < n; f++) {
for (idx = 0; *(dealloc[f] + idx) != NULL; idx++) {
free(*(dealloc[f] + idx));
}
free(dealloc[f]);
}
return WEXITSTATUS(status);
}
El código está escaneando y analizando otro programa, por eso es tanta la manipulación de cadenas, guardar y mirar hacia adelante en los caracteres y punteros.
Tuve cierto éxito con una herramienta llamada CppCheck a través de un sistema Jenkins CI. No realizo un seguimiento específico de las ramas condicionales, pero la cantidad de comprobaciones que proporciona esta herramienta merece la pena. En particular, verifique la Condition
parte que enumera varias verificaciones de condiciones que siempre son verdaderas/falsas (incluido el seguimiento de valores, condiciones duplicadas, lógica de intervalo), pero otras categorías también enumeran algunas verificaciones posiblemente útiles como:
Y está disponible como complemento para su IDE.
steve barnes
goto
, por lo que evita el uso de mantener, entonces no lo ha hecho bien.Niklas Rosencrantz
goto
pero en realidad me gusta porque es muy raro. Podemos hacerlo con 'break,
continue' que también me gusta más que las variables. De hecho, si programa en ensamblador lo hacegoto
a menudo.steve barnes
goto
algún lugar fuera de la función o procedimiento, no regresar. ¡Por eso es raro!Niklas Rosencrantz
goto
solo una vez porque era perezoso. Prometo cambiarlo por abreak
o acontinue
pero no me gustaboolean
...Ira Baxter
Niklas Rosencrantz
Ira Baxter
Ira Baxter
Niklas Rosencrantz
*(ptr + j)[0]
en realidad, es muy concreto el carácter actual de lo que se está escaneando,ptr
es el comienzo de la tubería y j es el desplazamiento. 0 significa el primer carácter del argumento. Especificación [aquí](pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html).Ira Baxter
Niklas Rosencrantz
fork
yexec
, pero los bucles son más rápidos y fáciles de codificar que la recursividad. Creo que la idea es buena para hacer una tabla de verdad para las condiciones para ver si algo siempre es o nunca es cierto porque hasta ahora no tengo experiencia en este nivel detallado de puntero C, pero estoy trabajando en ello. Puede encontrar el repositorio completo aquí para esta cosa, que es mi propio shell similar asash
odash
. Es interesante que Valgrind pueda Encontré mucho sobre la RAM, escribí una prueba que usa Valgrind.Ira Baxter
Tomás Weller
StefanS
StefanS
Ira Baxter
Niklas Rosencrantz
while
palabra claveexpr(A)::= WHILE LPAR expr(B) RPAR expr(C). {printf("test"); }
, pero la cadena de prueba no se imprime. Mi código se desordenó y estoy tratando de hacer una gramática en su lugar.Ira Baxter
Niklas Rosencrantz
while
palabra clave en función de la calculadora simple. Ahora dicen en la revisión del código hoy que mi código muestra "muchas" mejoras: codereview.stackexchange.com/questions/128149/…