diff --git a/README.md b/README.md index be6eb19..da1f3e9 100644 --- a/README.md +++ b/README.md @@ -587,7 +587,7 @@ Useful Parsers mpc_strip(mpc_parser_t *a);Matches a consuming any surrounding whitespace mpc_tok(mpc_parser_t *a);Matches a and consumes any trailing whitespace mpc_sym(const char *s);Matches string s and consumes any trailing whitespace - mpc_total(mpc_parser_t *a, mpc_dtor_t da);Matches the whitespace consumed a, enclosed in the start and end of input + mpc_total(mpc_parser_t *a, mpc_dtor_t da);Matches the whitespace consumed a, enclosed in the start and end of input mpc_between(mpc_parser_t *a, mpc_dtor_t ad,
const char *o, const char *c);
Matches a between strings o and c mpc_parens(mpc_parser_t *a, mpc_dtor_t ad);Matches a between "(" and ")" mpc_braces(mpc_parser_t *a, mpc_dtor_t ad);Matches a between "<" and ">" @@ -597,7 +597,7 @@ Useful Parsers mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace consumed "(" and ")" mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace consumed "<" and ">" mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace consumed "{" and "}" - mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace consumed "[" and "]" + mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace consumed "[" and "]" diff --git a/examples/foobar.c b/examples/foobar.c new file mode 100644 index 0000000..983974d --- /dev/null +++ b/examples/foobar.c @@ -0,0 +1,28 @@ +#include "../mpc.h" + +int main(int argc, char** argv) { + + mpc_result_t r; + mpc_parser_t* Foobar; + + if (argc != 2) { + printf("Usage: ./foobar \n"); + exit(0); + } + + Foobar = mpc_new("foobar"); + mpca_lang(MPCA_LANG_DEFAULT, "foobar : \"foo\" | \"bar\";", Foobar); + + if (mpc_parse("", argv[1], Foobar, &r)) { + mpc_ast_print(r.output); + mpc_ast_delete(r.output); + } else { + mpc_err_print(r.error); + mpc_err_delete(r.error); + } + + mpc_cleanup(1, Foobar); + + return 0; +} + diff --git a/mpc.c b/mpc.c index fce1f0c..2869ee4 100644 --- a/mpc.c +++ b/mpc.c @@ -122,13 +122,14 @@ void mpc_err_string_cat(char *buffer, int *pos, int *max, char const *fmt, ...) va_end(va); } -static char char_unescape_buffer[3]; +static char char_unescape_buffer[4]; static const char *mpc_err_char_unescape(char c) { char_unescape_buffer[0] = '\''; char_unescape_buffer[1] = ' '; char_unescape_buffer[2] = '\''; + char_unescape_buffer[3] = '\0'; switch (c) { @@ -149,11 +150,11 @@ static const char *mpc_err_char_unescape(char c) { } char *mpc_err_string(mpc_err_t *x) { - - char *buffer = calloc(1, 1024); - int max = 1023; + + int i; int pos = 0; - int i; + int max = 1023; + char *buffer = calloc(1, 1024); if (x->failure) { mpc_err_string_cat(buffer, &pos, &max, @@ -959,7 +960,7 @@ static mpc_err_t *mpc_stack_merger_err(mpc_stack_t *s, int n) { #define MPC_CONTINUE(st, x) mpc_stack_set_state(stk, st); mpc_stack_pushp(stk, x); continue #define MPC_SUCCESS(x) mpc_stack_popp(stk, &p, &st); mpc_stack_pushr(stk, mpc_result_out(x), 1); continue #define MPC_FAILURE(x) mpc_stack_popp(stk, &p, &st); mpc_stack_pushr(stk, mpc_result_err(x), 0); continue -#define MPC_PRIMATIVE(x, f) if (f) { MPC_SUCCESS(x); } else { MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Incorrect Input")); } +#define MPC_PRIMITIVE(x, f) if (f) { MPC_SUCCESS(x); } else { MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Incorrect Input")); } int mpc_parse_input(mpc_input_t *i, mpc_parser_t *init, mpc_result_t *final) { @@ -983,13 +984,13 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *init, mpc_result_t *final) { /* Basic Parsers */ - case MPC_TYPE_ANY: MPC_PRIMATIVE(s, mpc_input_any(i, &s)); - case MPC_TYPE_SINGLE: MPC_PRIMATIVE(s, mpc_input_char(i, p->data.single.x, &s)); - case MPC_TYPE_RANGE: MPC_PRIMATIVE(s, mpc_input_range(i, p->data.range.x, p->data.range.y, &s)); - case MPC_TYPE_ONEOF: MPC_PRIMATIVE(s, mpc_input_oneof(i, p->data.string.x, &s)); - case MPC_TYPE_NONEOF: MPC_PRIMATIVE(s, mpc_input_noneof(i, p->data.string.x, &s)); - case MPC_TYPE_SATISFY: MPC_PRIMATIVE(s, mpc_input_satisfy(i, p->data.satisfy.f, &s)); - case MPC_TYPE_STRING: MPC_PRIMATIVE(s, mpc_input_string(i, p->data.string.x, &s)); + case MPC_TYPE_ANY: MPC_PRIMITIVE(s, mpc_input_any(i, &s)); + case MPC_TYPE_SINGLE: MPC_PRIMITIVE(s, mpc_input_char(i, p->data.single.x, &s)); + case MPC_TYPE_RANGE: MPC_PRIMITIVE(s, mpc_input_range(i, p->data.range.x, p->data.range.y, &s)); + case MPC_TYPE_ONEOF: MPC_PRIMITIVE(s, mpc_input_oneof(i, p->data.string.x, &s)); + case MPC_TYPE_NONEOF: MPC_PRIMITIVE(s, mpc_input_noneof(i, p->data.string.x, &s)); + case MPC_TYPE_SATISFY: MPC_PRIMITIVE(s, mpc_input_satisfy(i, p->data.satisfy.f, &s)); + case MPC_TYPE_STRING: MPC_PRIMITIVE(s, mpc_input_string(i, p->data.string.x, &s)); /* Other parsers */ @@ -1147,7 +1148,7 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *init, mpc_result_t *final) { case MPC_TYPE_AND: - if (p->data.or.n == 0) { MPC_SUCCESS(p->data.and.f(0, NULL)); } + if (p->data.and.n == 0) { MPC_SUCCESS(p->data.and.f(0, NULL)); } if (st == 0) { mpc_input_mark(i); MPC_CONTINUE(st+1, p->data.and.xs[st]); } if (st <= p->data.and.n) { @@ -1176,7 +1177,7 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *init, mpc_result_t *final) { #undef MPC_CONTINUE #undef MPC_SUCCESS #undef MPC_FAILURE -#undef MPC_PRIMATIVE +#undef MPC_PRIMITIVE int mpc_parse(const char *filename, const char *string, mpc_parser_t *p, mpc_result_t *r) { int x; @@ -1945,12 +1946,12 @@ static const char *mpc_re_range_escape_char(char c) { static mpc_val_t *mpcf_re_range(mpc_val_t *x) { mpc_parser_t *out; - char *range = calloc(1,1); + size_t i, j; + size_t start, end; const char *tmp = NULL; const char *s = x; int comp = s[0] == '^' ? 1 : 0; - size_t start, end; - size_t i, j; + char *range = calloc(1,1); if (s[0] == '\0') { free(x); return mpc_fail("Invalid Regex Range Expression"); } if (s[0] == '^' && @@ -2144,9 +2145,9 @@ static mpc_val_t *mpcf_escape_new(mpc_val_t *x, const char *input, const char ** int i; int found; + char buff[2]; char *s = x; char *y = calloc(1, 1); - char buff[2]; while (*s) { @@ -2180,10 +2181,10 @@ static mpc_val_t *mpcf_unescape_new(mpc_val_t *x, const char *input, const char int i; int found = 0; + char buff[2]; char *s = x; char *y = calloc(1, 1); - char buff[2]; - + while (*s) { i = 0; @@ -2201,7 +2202,7 @@ static mpc_val_t *mpcf_unescape_new(mpc_val_t *x, const char *input, const char } i++; } - + if (!found) { y = realloc(y, strlen(y) + 2); buff[0] = *s; buff[1] = '\0'; @@ -2228,6 +2229,12 @@ mpc_val_t *mpcf_unescape(mpc_val_t *x) { return y; } +mpc_val_t *mpcf_escape_regex(mpc_val_t *x) { + mpc_val_t *y = mpcf_escape_new(x, mpc_escape_input_raw_re, mpc_escape_output_raw_re); + free(x); + return y; +} + mpc_val_t *mpcf_unescape_regex(mpc_val_t *x) { mpc_val_t *y = mpcf_unescape_new(x, mpc_escape_input_raw_re, mpc_escape_output_raw_re); free(x); @@ -2276,8 +2283,9 @@ mpc_val_t *mpcf_snd_free(int n, mpc_val_t **xs) { return mpcf_nth_free(n, xs, 1) mpc_val_t *mpcf_trd_free(int n, mpc_val_t **xs) { return mpcf_nth_free(n, xs, 2); } mpc_val_t *mpcf_strfold(int n, mpc_val_t **xs) { - char *x = calloc(1, 1); int i; + char *x = calloc(1, 1); + for (i = 0; i < n; i++) { x = realloc(x, strlen(x) + strlen(xs[i]) + 1); strcat(x, xs[i]); @@ -2499,6 +2507,7 @@ void mpc_ast_delete(mpc_ast_t *a) { int i; if (a == NULL) { return; } + for (i = 0; i < a->children_num; i++) { mpc_ast_delete(a->children[i]); } @@ -2612,6 +2621,12 @@ mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s) { static void mpc_ast_print_depth(mpc_ast_t *a, int d, FILE *fp) { int i; + + if (a == NULL) { + fprintf(fp, "NULL\n"); + return; + } + for (i = 0; i < d; i++) { fprintf(fp, " "); } if (strlen(a->contents)) { diff --git a/package.json b/package.json new file mode 100644 index 0000000..9e2bff1 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "mpc", + "version": "0.8.5", + "repo": "orangeduck/mpc", + "description": "A Parser Combinator library for C", + "keywords": ["parser", "combinator", "library", "c", "mpc"], + "license": "BSD", + "src": ["mpc.c", "mpc.h"] +} diff --git a/tests/ptest.c b/tests/ptest.c index aa8be74..de2d534 100644 --- a/tests/ptest.c +++ b/tests/ptest.c @@ -26,32 +26,47 @@ static int suite_passing = 0; /* Colors */ enum { - BLACK = 0x0, - BLUE = 0x1, - GREEN = 0x2, - AQUA = 0x3, - RED = 0x4, - PURPLE = 0x5, - YELLOW = 0x6, - WHITE = 0x7, - GRAY = 0x8, - LIGHT_BLUE = 0x9, - LIGHT_GREEN = 0xA, - LIGHT_AQUA = 0xB, - LIGHT_RED = 0xC, - LIGHT_PURPLE = 0xD, - LIGHT_YELLOW = 0xE, - LIGHT_WHITE = 0xF + BLACK = 0, + BLUE = 1, + GREEN = 2, + AQUA = 3, + RED = 4, + PURPLE = 5, + YELLOW = 6, + WHITE = 7, + GRAY = 8, + + LIGHT_BLUE = 9, + LIGHT_GREEN = 10, + LIGHT_AQUA = 11, + LIGHT_RED = 12, + LIGHT_PURPLE = 13, + LIGHT_YELLOW = 14, + LIGHT_WHITE = 15, + + DEFAULT = 16, }; #ifdef _WIN32 - #include +#include - static void pt_color(int color) { - HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); - SetConsoleTextAttribute(hCon, color); +static WORD defaults; +static int defaults_loaded = 0; + +static void pt_color(int color) { + + HANDLE cnsl = GetStdHandle(STD_OUTPUT_HANDLE); + + if (!defaults_loaded) { + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(cnsl, &info); + defaults = info.wAttributes; + defaults_loaded = 1; } + + SetConsoleTextAttribute(cnsl, color == DEFAULT ? defaults : color); +} #else @@ -71,14 +86,13 @@ static const char* colors[] = { "\x1B[31m", "\x1B[35m", "\x1B[33m", - "\x1B[37m" + "\x1B[37m", + "\x1B[39m", }; - static void pt_color(int color) { - - printf("%s", colors[color]); - - } +static void pt_color(int color) { + printf("%s", colors[color]); +} #endif @@ -92,16 +106,18 @@ static char assert_err[MAX_ERROR]; static char assert_err_buff[MAX_ERROR]; static int assert_err_num = 0; -void pt_assert_run(int result, const char* expr, const char* func, const char* file, int line) { +void pt_assert_run( + int result, const char* expr, const char* func, const char* file, int line) { - (void) func; num_asserts++; test_passing = test_passing && result; if (result) { num_assert_passes++; } else { - sprintf(assert_err_buff, " %i. Assert [ %s ] (%s:%i)\n", assert_err_num+1, expr, file, line ); + sprintf(assert_err_buff, + " %i. Assert [ %s ] (%s:%i)\n", + assert_err_num+1, expr, file, line ); strcat(assert_err, assert_err_buff); assert_err_num++; num_assert_fails++; @@ -110,22 +126,29 @@ void pt_assert_run(int result, const char* expr, const char* func, const char* f } static void ptest_signal(int sig) { - + test_passing = 0; switch( sig ) { - case SIGFPE: sprintf(assert_err_buff, " %i. Division by Zero\n", assert_err_num+1); break; - case SIGILL: sprintf(assert_err_buff, " %i. Illegal Instruction\n", assert_err_num+1); break; - case SIGSEGV: sprintf(assert_err_buff, " %i. Segmentation Fault\n", assert_err_num+1); break; - default: break; + case SIGFPE: sprintf(assert_err_buff, + " %i. Division by Zero\n", assert_err_num+1); + break; + case SIGILL: sprintf(assert_err_buff, + " %i. Illegal Instruction\n", assert_err_num+1); + break; + case SIGSEGV: sprintf(assert_err_buff, + " %i. Segmentation Fault\n", assert_err_num+1); + break; } assert_err_num++; strcat(assert_err, assert_err_buff); - pt_color(WHITE); pt_color(RED); printf("Failed! \n\n%s\n", assert_err); pt_color(WHITE); + pt_color(RED); + printf("Failed! \n\n%s\n", assert_err); + pt_color(DEFAULT); - printf(" | Stopping Execution.\n"); + puts(" | Stopping Execution."); fflush(stdout); exit(0); @@ -134,14 +157,14 @@ static void ptest_signal(int sig) { /* Tests */ static void pt_title_case(char* output, const char* input) { - + int space = 1; - size_t i; + unsigned int i; strcpy(output, input); for(i = 0; i < strlen(output); i++) { - + if (output[i] == '_' || output[i] == ' ') { space = 1; output[i] = ' '; @@ -173,19 +196,22 @@ static int num_tests_passes = 0; static int num_tests_fails = 0; void pt_add_test(void (*func)(void), const char* name, const char* suite) { - + test_t test; if (num_tests == MAX_TESTS) { - printf("ERROR: Exceeded maximum test count of %i!\n", MAX_TESTS); abort(); + printf("ERROR: Exceeded maximum test count of %i!\n", + MAX_TESTS); abort(); } if (strlen(name) >= MAX_NAME) { - printf("ERROR: Test name '%s' too long (Maximum is %i characters)\n", name, MAX_NAME); abort(); + printf("ERROR: Test name '%s' too long (Maximum is %i characters)\n", + name, MAX_NAME); abort(); } if (strlen(suite) >= MAX_NAME) { - printf("ERROR: Test suite '%s' too long (Maximum is %i characters)\n", suite, MAX_NAME); abort(); + printf("ERROR: Test suite '%s' too long (Maximum is %i characters)\n", + suite, MAX_NAME); abort(); } test.func = func; @@ -194,7 +220,6 @@ void pt_add_test(void (*func)(void), const char* name, const char* suite) { tests[num_tests] = test; num_tests++; - } /* Suites */ @@ -215,17 +240,18 @@ static char current_suite[MAX_NAME]; int pt_run(void) { - int i; + unsigned int i; double total; + test_t test; - printf(" \n"); - printf(" +-------------------------------------------+\n"); - printf(" | ptest MicroTesting Magic for C |\n"); - printf(" | |\n"); - printf(" | http://github.com/orangeduck/ptest |\n"); - printf(" | |\n"); - printf(" | Daniel Holden (contact@theorangeduck.com) |\n"); - printf(" +-------------------------------------------+\n"); + puts(""); + puts(" +-------------------------------------------+"); + puts(" | ptest MicroTesting Magic for C |"); + puts(" | |"); + puts(" | http://github.com/orangeduck/ptest |"); + puts(" | |"); + puts(" | Daniel Holden (contact@theorangeduck.com) |"); + puts(" +-------------------------------------------+"); signal(SIGFPE, ptest_signal); signal(SIGILL, ptest_signal); @@ -235,12 +261,12 @@ int pt_run(void) { strcpy(current_suite, ""); for(i = 0; i < num_tests; i++) { - - test_t test = tests[i]; + + test = tests[i]; /* Check for transition to a new suite */ if (strcmp(test.suite, current_suite)) { - + /* Don't increment any counter for first entrance */ if (strcmp(current_suite, "")) { if (suite_passing) { @@ -262,6 +288,7 @@ int pt_run(void) { strcpy(assert_err_buff, ""); assert_err_num = 0; printf(" | %s ... ", test.name); + fflush(stdout); test.func(); @@ -269,10 +296,14 @@ int pt_run(void) { if (test_passing) { num_tests_passes++; - pt_color(GREEN); printf("Passed! \n"); pt_color(WHITE); + pt_color(GREEN); + puts("Passed!"); + pt_color(DEFAULT); } else { num_tests_fails++; - pt_color(RED); printf("Failed! \n\n%s\n", assert_err); pt_color(WHITE); + pt_color(RED); + printf("Failed! \n\n%s\n", assert_err); + pt_color(DEFAULT); } } @@ -285,28 +316,37 @@ int pt_run(void) { end = clock(); - printf(" \n"); - printf(" +---------------------------------------------------+\n"); - printf(" | Summary |\n"); - printf(" +---------++------------+-------------+-------------+\n"); + puts(""); + puts(" +---------------------------------------------------+"); + puts(" | Summary |"); + puts(" +---------++------------+-------------+-------------+"); printf(" | Suites ||"); - pt_color(YELLOW); printf(" Total %4d ", num_suites); pt_color(WHITE); printf("|"); - pt_color(GREEN); printf(" Passed %4d ", num_suites_passes); pt_color(WHITE); printf("|"); - pt_color(RED); printf(" Failed %4d ", num_suites_fails); pt_color(WHITE); printf("|\n"); + pt_color(YELLOW); printf(" Total %4d ", num_suites); + pt_color(DEFAULT); putchar('|'); + pt_color(GREEN); printf(" Passed %4d ", num_suites_passes); + pt_color(DEFAULT); putchar('|'); + pt_color(RED); printf(" Failed %4d ", num_suites_fails); + pt_color(DEFAULT); puts("|"); printf(" | Tests ||"); - pt_color(YELLOW); printf(" Total %4d ", num_tests); pt_color(WHITE); printf("|"); - pt_color(GREEN); printf(" Passed %4d ", num_tests_passes); pt_color(WHITE); printf("|"); - pt_color(RED); printf(" Failed %4d ", num_tests_fails); pt_color(WHITE); printf("|\n"); + pt_color(YELLOW); printf(" Total %4d ", num_tests); + pt_color(DEFAULT); putchar('|'); + pt_color(GREEN); printf(" Passed %4d ", num_tests_passes); + pt_color(DEFAULT); putchar('|'); + pt_color(RED); printf(" Failed %4d ", num_tests_fails); + pt_color(DEFAULT); puts("|"); printf(" | Asserts ||"); - pt_color(YELLOW); printf(" Total %4d ", num_asserts); pt_color(WHITE); printf("|"); - pt_color(GREEN); printf(" Passed %4d ", num_assert_passes); pt_color(WHITE); printf("|"); - pt_color(RED); printf(" Failed %4d ", num_assert_fails); pt_color(WHITE); printf("|\n"); + pt_color(YELLOW); printf(" Total %4d ", num_asserts); + pt_color(DEFAULT); putchar('|'); + pt_color(GREEN); printf(" Passed %4d ", num_assert_passes); + pt_color(DEFAULT); putchar('|'); + pt_color(RED); printf(" Failed %4d ", num_assert_fails); + pt_color(DEFAULT); puts("|"); - printf(" +---------++------------+-------------+-------------+\n"); - printf(" \n"); + puts(" +---------++------------+-------------+-------------+"); + puts(""); total = (double)(end - start) / CLOCKS_PER_SEC; diff --git a/tests/ptest.h b/tests/ptest.h index 4de173f..8c436cd 100644 --- a/tests/ptest.h +++ b/tests/ptest.h @@ -18,5 +18,4 @@ void pt_add_test(void (*func)(void), const char* name, const char* suite); void pt_add_suite(void (*func)(void)); int pt_run(void); -#endif - +#endif \ No newline at end of file