143 lines
4.4 KiB
C
143 lines
4.4 KiB
C
// This is a personal academic project. Dear PVS-Studio, please check it.
|
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "parser_utils.h"
|
|
|
|
const char * parser_utils_strcmpi_event(const enum string_cmp_event_types type) {
|
|
const char *ret;
|
|
|
|
switch (type) {
|
|
case STRING_CMP_MAYEQ:
|
|
ret = "wait(c)";
|
|
break;
|
|
case STRING_CMP_EQ:
|
|
ret = "eq(c)";
|
|
break;
|
|
case STRING_CMP_NEQ:
|
|
ret = "neq(c)";
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void may_eq(struct parser_event *ret, const uint8_t c) {
|
|
ret->type = STRING_CMP_MAYEQ;
|
|
ret->n = 1;
|
|
ret->data[0] = c;
|
|
}
|
|
|
|
static void eq(struct parser_event *ret, const uint8_t c) {
|
|
ret->type = STRING_CMP_EQ;
|
|
ret->n = 1;
|
|
ret->data[0] = c;
|
|
}
|
|
|
|
static void neq(struct parser_event *ret, const uint8_t c) {
|
|
ret->type = STRING_CMP_NEQ;
|
|
ret->n = 1;
|
|
ret->data[0] = c;
|
|
}
|
|
|
|
/*
|
|
* para comparar "foo" (length 3) necesitamos 3 + 2 estados.
|
|
* Los útimos dos, son el sumidero de comparación fallida, y
|
|
* el estado donde se llegó a la comparación completa.
|
|
*
|
|
* static const struct parser_state_transition ST_0 [] = {
|
|
* {.when = 'F', .dest = 1, .action1 = may_eq, },
|
|
* {.when = 'f', .dest = 1, .action1 = may_eq, },
|
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
|
* };
|
|
* static const struct parser_state_transition ST_1 [] = {
|
|
* {.when = 'O', .dest = 2, .action1 = may_eq, },
|
|
* {.when = 'o', .dest = 2, .action1 = may_eq, },
|
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
|
* };
|
|
* static const struct parser_state_transition ST_2 [] = {
|
|
* {.when = 'O', .dest = EQ, .action1 = eq, },
|
|
* {.when = 'o', .dest = EQ, .action1 = eq, },
|
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
|
* };
|
|
* static const struct parser_state_transition ST_EQ (3) [] = {
|
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
|
* };
|
|
* static const struct parser_state_transition ST_NEQ (4) [] = {
|
|
* {.when = ANY, .dest = NEQ, .action1 = neq,},
|
|
* };
|
|
*
|
|
*/
|
|
struct parser_definition parser_utils_strcmpi(const char *s) {
|
|
const size_t n = strlen(s);
|
|
|
|
struct parser_state_transition **states = calloc(n + 2, sizeof(*states));
|
|
size_t *nstates = calloc(n + 2, sizeof(*nstates));
|
|
struct parser_state_transition *transitions = calloc(3 * (n + 2), sizeof(*transitions));
|
|
|
|
if (states == NULL || nstates == NULL || transitions == NULL) {
|
|
free(states);
|
|
free(nstates);
|
|
free(transitions);
|
|
|
|
struct parser_definition def = {
|
|
.start_state = 0,
|
|
.states_count = 0,
|
|
.states = NULL,
|
|
.states_n = NULL,
|
|
};
|
|
return def;
|
|
}
|
|
|
|
// estados fijos
|
|
const size_t st_eq = n;
|
|
const size_t st_neq = n + 1;
|
|
|
|
for(size_t i = 0; i < n; i++) {
|
|
const size_t dest = (i + 1 == n) ? st_eq : i + 1;
|
|
|
|
transitions[i * 3 + 0].when = tolower(s[i]);
|
|
transitions[i * 3 + 0].dest = dest;
|
|
transitions[i * 3 + 0].act1 = i + 1 == n ? eq : may_eq;
|
|
transitions[i * 3 + 1].when = toupper(s[i]);
|
|
transitions[i * 3 + 1].dest = dest;
|
|
transitions[i * 3 + 1].act1 = i + 1 == n ? eq : may_eq;
|
|
transitions[i * 3 + 2].when = ANY;
|
|
transitions[i * 3 + 2].dest = st_neq;
|
|
transitions[i * 3 + 2].act1 = neq;
|
|
states[i] = transitions + (i * 3 + 0);
|
|
nstates[i] = 3;
|
|
}
|
|
|
|
// EQ
|
|
transitions[(n + 0) * 3].when = ANY;
|
|
transitions[(n + 0) * 3].dest = st_neq;
|
|
transitions[(n + 0) * 3].act1 = neq;
|
|
states[(n + 0)] = transitions + ((n + 0) * 3 + 0);
|
|
nstates[(n + 0)] = 1;
|
|
|
|
// NEQ
|
|
transitions[(n + 1) * 3].when = ANY;
|
|
transitions[(n + 1) * 3].dest = st_neq;
|
|
transitions[(n + 1) * 3].act1 = neq;
|
|
states[(n + 1)] = transitions + ((n + 1) * 3 + 0);
|
|
nstates[(n + 1)] = 1;
|
|
|
|
|
|
struct parser_definition def = {
|
|
.start_state = 0,
|
|
.states_count = n + 2,
|
|
.states = (const struct parser_state_transition **) states,
|
|
.states_n = (const size_t *) nstates,
|
|
};
|
|
|
|
return def;
|
|
}
|
|
|
|
void parser_utils_strcmpi_destroy(const struct parser_definition *p) {
|
|
free((void *)p->states[0]);
|
|
free((void *)p->states);
|
|
free((void *)p->states_n);
|
|
}
|