From 308ad96c757a70b04fd613678318112f1df6af8e Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 30 Nov 2014 15:52:22 +0000 Subject: [PATCH 01/49] Update mpc.c --- mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpc.c b/mpc.c index f9cced1..4c143df 100644 --- a/mpc.c +++ b/mpc.c @@ -1147,7 +1147,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) { From c6a43cafe8c709808916aa8c1ffacd7219407dd9 Mon Sep 17 00:00:00 2001 From: TTiga Date: Thu, 4 Dec 2014 15:01:58 +0800 Subject: [PATCH 02/49] add a unimplemented library function --- mpc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mpc.c b/mpc.c index 4c143df..a6cd10e 100644 --- a/mpc.c +++ b/mpc.c @@ -2207,6 +2207,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); From af6e3db69e4afe858bb2bbcd1ab4aee97ada0ff1 Mon Sep 17 00:00:00 2001 From: David Roth Date: Wed, 10 Dec 2014 11:55:38 -0500 Subject: [PATCH 03/49] Fix typos: 'MPC_PRIMITIVE' (mpc.c), and 'stripped'/'stripping' (README.md) --- README.md | 8 ++++---- mpc.c | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f8a46e6..7ec1a59 100644 --- a/README.md +++ b/README.md @@ -582,9 +582,9 @@ Useful Parsers mpc_startswith(mpc_parser_t *a);Matches the start of input followed by a mpc_endswith(mpc_parser_t *a, mpc_dtor_t da);Matches a followed by the end of input mpc_whole(mpc_parser_t *a, mpc_dtor_t da);Matches the start of input, a, and the end of input - mpc_stripl(mpc_parser_t *a);Matches a striping any whitespace to the left - mpc_stripr(mpc_parser_t *a);Matches a striping any whitespace to the right - mpc_strip(mpc_parser_t *a);Matches a striping any surrounding whitespace + mpc_stripl(mpc_parser_t *a);Matches a stripping any whitespace to the left + mpc_stripr(mpc_parser_t *a);Matches a stripping any whitespace to the right + mpc_strip(mpc_parser_t *a);Matches a stripping any surrounding whitespace mpc_tok(mpc_parser_t *a);Matches a and strips any trailing whitespace mpc_sym(const char *s);Matches string s and strips any trailing whitespace mpc_total(mpc_parser_t *a, mpc_dtor_t da);Matches the whitespace stripped a, enclosed in the start and end of input @@ -593,7 +593,7 @@ Useful Parsers mpc_braces(mpc_parser_t *a, mpc_dtor_t ad);Matches a between "<" and ">" mpc_brackets(mpc_parser_t *a, mpc_dtor_t ad);Matches a between "{" and "}" mpc_squares(mpc_parser_t *a, mpc_dtor_t ad);Matches a between "[" and "]" - mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad,
const char *o, const char *c);
Matches a between o and c, where o and c have their trailing whitespace striped. + mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad,
const char *o, const char *c);
Matches a between o and c, where o and c have their trailing whitespace stripped. mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace stripped "(" and ")" mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace stripped "<" and ">" mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace stripped "{" and "}" diff --git a/mpc.c b/mpc.c index a6cd10e..1a9591c 100644 --- a/mpc.c +++ b/mpc.c @@ -959,7 +959,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 +983,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 */ @@ -1176,7 +1176,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; From 9481c6573cb0a13fdce7801f04c3395ba4a1b6b5 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 7 Feb 2015 19:26:35 +0000 Subject: [PATCH 04/49] Fixed odd bug with calloc --- examples/foobar.c | 20 ++++++++++++++++++++ mpc.c | 25 +++++++++++++------------ 2 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 examples/foobar.c diff --git a/examples/foobar.c b/examples/foobar.c new file mode 100644 index 0000000..43691f7 --- /dev/null +++ b/examples/foobar.c @@ -0,0 +1,20 @@ +#include "../mpc.h" + +int main(int argc, char** argv) { + + mpc_result_t r; + mpc_parser_t* Foobar = mpc_new("foobar"); + mpca_lang(MPCA_LANG_DEFAULT, "foobar : \"foo\" | \"bar\";", Foobar); + (void)argc; + + 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 1a9591c..99de0d9 100644 --- a/mpc.c +++ b/mpc.c @@ -149,11 +149,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, @@ -1945,12 +1945,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] == '^' && @@ -2123,9 +2123,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) { @@ -2159,10 +2159,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; @@ -2180,7 +2180,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'; @@ -2261,8 +2261,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]); From c4c963f3b331dca61404d1df47e2d587b9d06df6 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 7 Feb 2015 19:41:33 +0000 Subject: [PATCH 05/49] Updated foobar example --- examples/foobar.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/foobar.c b/examples/foobar.c index 43691f7..983974d 100644 --- a/examples/foobar.c +++ b/examples/foobar.c @@ -3,9 +3,15 @@ int main(int argc, char** argv) { mpc_result_t r; - mpc_parser_t* Foobar = mpc_new("foobar"); + 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); - (void)argc; if (mpc_parse("", argv[1], Foobar, &r)) { mpc_ast_print(r.output); @@ -14,7 +20,9 @@ int main(int argc, char** argv) { mpc_err_print(r.error); mpc_err_delete(r.error); } + mpc_cleanup(1, Foobar); + return 0; } From d6347af7b4aa70b79546106c4ce8a9ae273208f7 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 8 Feb 2015 10:45:14 +0000 Subject: [PATCH 06/49] Fixed null termination bug in error printing --- mpc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mpc.c b/mpc.c index 99de0d9..be9d88b 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) { From 818aa81638d2478903e069235f154e9974fa3755 Mon Sep 17 00:00:00 2001 From: Giovanny Andres Gongora Granada Date: Mon, 9 Feb 2015 23:02:17 -0500 Subject: [PATCH 07/49] live on clibs --- package.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 package.json 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"] +} From 7ab31406175445e2cdbaa052f892f98e1590c30b Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 22 Feb 2015 17:22:34 +0000 Subject: [PATCH 08/49] Updated to newer version of ptest --- tests/ptest.c | 186 ++++++++++++++++++++++++++++++-------------------- tests/ptest.h | 3 +- 2 files changed, 114 insertions(+), 75 deletions(-) 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 From 3878cd76e6de75d4427219c823947fac19a29a4f Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 22 Feb 2015 17:38:47 +0000 Subject: [PATCH 09/49] print function now works for null tree --- mpc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mpc.c b/mpc.c index be9d88b..d099daf 100644 --- a/mpc.c +++ b/mpc.c @@ -2486,6 +2486,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]); } @@ -2599,6 +2600,11 @@ 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"); + } + for (i = 0; i < d; i++) { fprintf(fp, " "); } if (strlen(a->contents)) { From 24478bd6f4883f969fd88cb978ea06afcf36939f Mon Sep 17 00:00:00 2001 From: Michael Casebolt Date: Tue, 3 Mar 2015 15:40:04 -0800 Subject: [PATCH 10/49] Return from mpc_ast_print_depth if NULL Return from mpc_ast_print_depth after printing 'NULL' to avoid the potential segfault. --- mpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mpc.c b/mpc.c index d099daf..5c96ba7 100644 --- a/mpc.c +++ b/mpc.c @@ -2603,6 +2603,7 @@ static void mpc_ast_print_depth(mpc_ast_t *a, int d, FILE *fp) { if (a == NULL) { fprintf(fp, "NULL\n"); + return; } for (i = 0; i < d; i++) { fprintf(fp, " "); } From 123a7919d1ed2f51d369a9327ea9464f0e146594 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Tue, 10 Mar 2015 10:44:29 +0000 Subject: [PATCH 11/49] Added string stripping functions --- Makefile | 8 ++++---- README.md | 20 ++++++++++---------- mpc.c | 23 ++++++++++++++++++++++- mpc.h | 4 ++++ tests/core.c | 35 ++++++++++++++++++++++++++--------- 5 files changed, 66 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index acac791..9df01fc 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ CC = gcc STND=-ansi -CFLAGS = $(STND) -pedantic -O3 -g -Werror -Wall -Wextra -Wformat=2 -Wshadow -Wno-long-long \ - -Wno-overlength-strings -Wno-format-nonliteral -Wcast-align \ - -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wredundant-decls -Wnested-externs \ - -Wmissing-include-dirs -Wswitch-default +CFLAGS = $(STND) -pedantic -O3 -g -Werror -Wall -Wextra -Wformat=2 -Wshadow \ + -Wno-long-long -Wno-overlength-strings -Wno-format-nonliteral -Wcast-align \ + -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wredundant-decls \ + -Wnested-externs -Wmissing-include-dirs -Wswitch-default TESTS = $(wildcard tests/*.c) EXAMPLES = $(wildcard examples/*.c) diff --git a/README.md b/README.md index f8a46e6..be6eb19 100644 --- a/README.md +++ b/README.md @@ -582,22 +582,22 @@ Useful Parsers mpc_startswith(mpc_parser_t *a);Matches the start of input followed by a mpc_endswith(mpc_parser_t *a, mpc_dtor_t da);Matches a followed by the end of input mpc_whole(mpc_parser_t *a, mpc_dtor_t da);Matches the start of input, a, and the end of input - mpc_stripl(mpc_parser_t *a);Matches a striping any whitespace to the left - mpc_stripr(mpc_parser_t *a);Matches a striping any whitespace to the right - mpc_strip(mpc_parser_t *a);Matches a striping any surrounding whitespace - mpc_tok(mpc_parser_t *a);Matches a and strips any trailing whitespace - mpc_sym(const char *s);Matches string s and strips any trailing whitespace - mpc_total(mpc_parser_t *a, mpc_dtor_t da);Matches the whitespace stripped a, enclosed in the start and end of input + mpc_stripl(mpc_parser_t *a);Matches a first consuming any whitespace to the left + mpc_stripr(mpc_parser_t *a);Matches a then consumes any whitespace to the right + 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_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 ">" mpc_brackets(mpc_parser_t *a, mpc_dtor_t ad);Matches a between "{" and "}" mpc_squares(mpc_parser_t *a, mpc_dtor_t ad);Matches a between "[" and "]" mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad,
const char *o, const char *c);
Matches a between o and c, where o and c have their trailing whitespace striped. - mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace stripped "(" and ")" - mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace stripped "<" and ">" - mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace stripped "{" and "}" - mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);Matches a between trailing whitespace stripped "[" and "]" + 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 "]" diff --git a/mpc.c b/mpc.c index f9cced1..fce1f0c 100644 --- a/mpc.c +++ b/mpc.c @@ -2096,12 +2096,33 @@ mpc_val_t *mpcf_oct(mpc_val_t *x) { } mpc_val_t *mpcf_float(mpc_val_t *x) { - float* y = malloc(sizeof(float)); + float *y = malloc(sizeof(float)); *y = strtod(x, NULL); free(x); return y; } +mpc_val_t *mpcf_strtriml(mpc_val_t *x) { + char *s = x; + while (isspace(*s)) { + memmove(s, s+1, strlen(s)); + } + return s; +} + +mpc_val_t *mpcf_strtrimr(mpc_val_t *x) { + char *s = x; + size_t l = strlen(s); + while (isspace(s[l-1])) { + s[l-1] = '\0'; l--; + } + return s; +} + +mpc_val_t *mpcf_strtrim(mpc_val_t *x) { + return mpcf_strtriml(mpcf_strtrimr(x)); +} + static const char mpc_escape_input_c[] = { '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\'', '\"', '\0'}; diff --git a/mpc.h b/mpc.h index 9ea77dd..e75685c 100644 --- a/mpc.h +++ b/mpc.h @@ -16,6 +16,7 @@ #include #include #include +#include /* ** State Type @@ -218,6 +219,9 @@ mpc_val_t *mpcf_int(mpc_val_t *x); mpc_val_t *mpcf_hex(mpc_val_t *x); mpc_val_t *mpcf_oct(mpc_val_t *x); mpc_val_t *mpcf_float(mpc_val_t *x); +mpc_val_t *mpcf_strtriml(mpc_val_t *x); +mpc_val_t *mpcf_strtrimr(mpc_val_t *x); +mpc_val_t *mpcf_strtrim(mpc_val_t *x); mpc_val_t *mpcf_escape(mpc_val_t *x); mpc_val_t *mpcf_escape_regex(mpc_val_t *x); diff --git a/tests/core.c b/tests/core.c index abb2ea8..516e2ae 100644 --- a/tests/core.c +++ b/tests/core.c @@ -6,8 +6,8 @@ static int int_eq(const void* x, const void* y) { return (*(int*)x == *(int*)y); } static void int_print(const void* x) { printf("'%i'", *((int*)x)); } -static int string_eq(const void* x, const void* y) { return (strcmp(x, y) == 0); } -static void string_print(const void* x) { printf("'%s'", (char*)x); } +static int streq(const void* x, const void* y) { return (strcmp(x, y) == 0); } +static void strprint(const void* x) { printf("'%s'", (char*)x); } void test_ident(void) { @@ -21,13 +21,13 @@ void test_ident(void) { free ); - PT_ASSERT(mpc_test_pass(Ident, "test", "test", string_eq, free, string_print)); - PT_ASSERT(mpc_test_fail(Ident, " blah", "", string_eq, free, string_print)); - PT_ASSERT(mpc_test_pass(Ident, "anoth21er", "anoth21er", string_eq, free, string_print)); - PT_ASSERT(mpc_test_pass(Ident, "du__de", "du__de", string_eq, free, string_print)); - PT_ASSERT(mpc_test_fail(Ident, "some spaces", "", string_eq, free, string_print)); - PT_ASSERT(mpc_test_fail(Ident, "", "", string_eq, free, string_print)); - PT_ASSERT(mpc_test_fail(Ident, "18nums", "", string_eq, free, string_print)); + PT_ASSERT(mpc_test_pass(Ident, "test", "test", streq, free, strprint)); + PT_ASSERT(mpc_test_fail(Ident, " blah", "", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(Ident, "anoth21er", "anoth21er", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(Ident, "du__de", "du__de", streq, free, strprint)); + PT_ASSERT(mpc_test_fail(Ident, "some spaces", "", streq, free, strprint)); + PT_ASSERT(mpc_test_fail(Ident, "", "", streq, free, strprint)); + PT_ASSERT(mpc_test_fail(Ident, "18nums", "", streq, free, strprint)); mpc_delete(Ident); @@ -69,7 +69,24 @@ void test_maths(void) { mpc_cleanup(4, Expr, Factor, Term, Maths); } +void test_strip(void) { + + mpc_parser_t *Stripperl = mpc_apply(mpc_many(mpcf_strfold, mpc_any()), mpcf_strtriml); + mpc_parser_t *Stripperr = mpc_apply(mpc_many(mpcf_strfold, mpc_any()), mpcf_strtrimr); + mpc_parser_t *Stripper = mpc_apply(mpc_many(mpcf_strfold, mpc_any()), mpcf_strtrim); + + PT_ASSERT(mpc_test_pass(Stripperl, " asdmlm dasd ", "asdmlm dasd ", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(Stripperr, " asdmlm dasd ", " asdmlm dasd", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(Stripper, " asdmlm dasd ", "asdmlm dasd", streq, free, strprint)); + + mpc_delete(Stripperl); + mpc_delete(Stripperr); + mpc_delete(Stripper); + +} + void suite_core(void) { pt_add_test(test_ident, "Test Ident", "Suite Core"); pt_add_test(test_maths, "Test Maths", "Suite Core"); + pt_add_test(test_strip, "Test Strip", "Suite Core"); } From 6a8dc2e3f96fdee22db64256165b945ecc16bfda Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Tue, 10 Mar 2015 10:50:29 +0000 Subject: [PATCH 12/49] Fixed ptest compile errors --- tests/ptest.c | 8 ++++---- tests/ptest.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/ptest.c b/tests/ptest.c index de2d534..f5ffc8d 100644 --- a/tests/ptest.c +++ b/tests/ptest.c @@ -44,7 +44,7 @@ enum { LIGHT_YELLOW = 14, LIGHT_WHITE = 15, - DEFAULT = 16, + DEFAULT = 16 }; #ifdef _WIN32 @@ -106,8 +106,7 @@ 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* file, int line) { num_asserts++; test_passing = test_passing && result; @@ -139,6 +138,7 @@ static void ptest_signal(int sig) { case SIGSEGV: sprintf(assert_err_buff, " %i. Segmentation Fault\n", assert_err_num+1); break; + default: break; } assert_err_num++; @@ -240,7 +240,7 @@ static char current_suite[MAX_NAME]; int pt_run(void) { - unsigned int i; + int i; double total; test_t test; diff --git a/tests/ptest.h b/tests/ptest.h index 8c436cd..43ca3b5 100644 --- a/tests/ptest.h +++ b/tests/ptest.h @@ -6,13 +6,13 @@ #define PT_SUITE(name) void name(void) #define PT_FUNC(name) static void name(void) -#define PT_REG(name) pt_add_test(name, #name, __func__) +#define PT_REG(name) pt_add_test(name, #name) #define PT_TEST(name) auto void name(void); PT_REG(name); void name(void) -#define PT_ASSERT(expr) pt_assert_run((int)(expr), #expr, __func__, __FILE__, __LINE__) -#define PT_ASSERT_STR_EQ(fst, snd) pt_assert_run(strcmp(fst, snd) == 0, "strcmp( " #fst ", " #snd " ) == 0", __func__, __FILE__, __LINE__) +#define PT_ASSERT(expr) pt_assert_run((int)(expr), #expr, __FILE__, __LINE__) +#define PT_ASSERT_STR_EQ(fst, snd) pt_assert_run(strcmp(fst, snd) == 0, "strcmp( " #fst ", " #snd " ) == 0", __FILE__, __LINE__) -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* file, int line); void pt_add_test(void (*func)(void), const char* name, const char* suite); void pt_add_suite(void (*func)(void)); From 90af71c997896ec6c6efa7ac5643357265e82fcc Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Wed, 11 Mar 2015 09:43:01 +0000 Subject: [PATCH 13/49] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index da1f3e9..cdf642e 100644 --- a/README.md +++ b/README.md @@ -555,7 +555,7 @@ Common Parsers mpc_digitsMatches one or more digit mpc_hexdigitsMatches one or more hexdigit mpc_octdigitsMatches one or more octdigit - mpc_lowerMatches and lower case character + mpc_lowerMatches any lower case character mpc_upperMatches any upper case character mpc_alphaMatches and alphabet character mpc_underscoreMatches '_' @@ -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 "]" From 8c73fd20ddd71ebe4f9623201d1447314973f98f Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Wed, 11 Mar 2015 09:43:44 +0000 Subject: [PATCH 14/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cdf642e..58b7d12 100644 --- a/README.md +++ b/README.md @@ -557,7 +557,7 @@ Common Parsers mpc_octdigitsMatches one or more octdigit mpc_lowerMatches any lower case character mpc_upperMatches any upper case character - mpc_alphaMatches and alphabet character + mpc_alphaMatches any alphabet character mpc_underscoreMatches '_' mpc_alphanumMatches any alphabet character, underscore or digit mpc_intMatches digits and returns an int* From e85cbe9634da500306cae8a964cab5943043f300 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Wed, 11 Mar 2015 09:47:16 +0000 Subject: [PATCH 15/49] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 58b7d12..fdc2a0f 100644 --- a/README.md +++ b/README.md @@ -623,7 +623,9 @@ Apply Functions mpc_val_t *mpcf_unescape_regex(mpc_val_t *x);Converts a regex x to an unescaped version mpc_val_t *mpcf_unescape_string_raw(mpc_val_t *x);Converts a raw string x to an unescaped version mpc_val_t *mpcf_unescape_char_raw(mpc_val_t *x);Converts a raw character x to an unescaped version - + mpc_val_t *mpcf_strtriml(mpc_val_t *x);Trims whitespace from the left of string x + mpc_val_t *mpcf_strtrimr(mpc_val_t *x);Trims whitespace from the right of string x + mpc_val_t *mpcf_strtrim(mpc_val_t *x);Trims whitespace from either side of string x From 81abc6f115911c36923cd37d94476969043a02db Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Wed, 11 Mar 2015 09:48:10 +0000 Subject: [PATCH 16/49] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fdc2a0f..d094d39 100644 --- a/README.md +++ b/README.md @@ -623,9 +623,9 @@ Apply Functions mpc_val_t *mpcf_unescape_regex(mpc_val_t *x);Converts a regex x to an unescaped version mpc_val_t *mpcf_unescape_string_raw(mpc_val_t *x);Converts a raw string x to an unescaped version mpc_val_t *mpcf_unescape_char_raw(mpc_val_t *x);Converts a raw character x to an unescaped version - mpc_val_t *mpcf_strtriml(mpc_val_t *x);Trims whitespace from the left of string x - mpc_val_t *mpcf_strtrimr(mpc_val_t *x);Trims whitespace from the right of string x - mpc_val_t *mpcf_strtrim(mpc_val_t *x);Trims whitespace from either side of string x + mpc_val_t *mpcf_strtriml(mpc_val_t *x);Trims whitespace from the left of string x + mpc_val_t *mpcf_strtrimr(mpc_val_t *x);Trims whitespace from the right of string x + mpc_val_t *mpcf_strtrim(mpc_val_t *x);Trims whitespace from either side of string x From 3643fbe6bb1a4fa88db62b24c7a67c3399d64086 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Fri, 28 Aug 2015 19:20:39 +0100 Subject: [PATCH 17/49] Fixed bug in behaviour of counting parser. Removed changelog (git is the changelog). --- CHANGELOG.txt | 17 ----------------- README.md | 2 +- mpc.c | 18 ++++++++---------- tests/core.c | 38 ++++++++++++++++++++++++++++++++++---- 4 files changed, 43 insertions(+), 32 deletions(-) delete mode 100644 CHANGELOG.txt diff --git a/CHANGELOG.txt b/CHANGELOG.txt deleted file mode 100644 index 9c7f2dc..0000000 --- a/CHANGELOG.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Oct. 17, 2014; Daniel Holden -- Reverted state to use long type - -# Oct. 16, 2014; Daniel Holden -- Removed comments describing changes -- Fixed warnings reported by gcc in test suite under the new compilation flags - -# Oct. 14, 2014; Dalton Woodard -- Fixed all compilation warnings in `mpc.h` and `mpc.c`; both now compile successfully on OS X under clang-600.0.51 -and gcc 4.9.1 with the following flags: -``` --std=c11 -O3 -g -Werror -Wall -Wextra -Wformat=2 -Wshadow -Wno-format-nonliteral -Wcast-align -Wwrite-strings --Wstrict-prototypes -Wold-style-definition -Wredundant-decls -Wnested-externs -Wmissing-include-dirs -Wswitch-default -``` -- Changed compilation standard from ansi to c11. -- Further small changes in source (documented in-line). - diff --git a/README.md b/README.md index d094d39..c2d6192 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Micro Parser Combinators ======================== -Version 0.8.5 +Version 0.8.6 About diff --git a/mpc.c b/mpc.c index 2869ee4..26985f5 100644 --- a/mpc.c +++ b/mpc.c @@ -1112,19 +1112,17 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *init, mpc_result_t *final) { case MPC_TYPE_COUNT: if (st == 0) { mpc_input_mark(i); MPC_CONTINUE(st+1, p->data.repeat.x); } if (st > 0) { - if (mpc_stack_peekr(stk, &r)) { - MPC_CONTINUE(st+1, p->data.repeat.x); + if (!mpc_stack_peekr(stk, &r)) { + mpc_stack_popr(stk, &r); + mpc_stack_popr_out_single(stk, st-1, p->data.repeat.dx); + mpc_input_rewind(i); + MPC_FAILURE(mpc_err_count(r.error, p->data.repeat.n)); } else { - if (st != (p->data.repeat.n+1)) { - mpc_stack_popr(stk, &r); - mpc_stack_popr_out_single(stk, st-1, p->data.repeat.dx); - mpc_input_rewind(i); - MPC_FAILURE(mpc_err_count(r.error, p->data.repeat.n)); + if (st < p->data.repeat.n) { + MPC_CONTINUE(st+1, p->data.repeat.x); } else { - mpc_stack_popr(stk, &r); - mpc_stack_err(stk, r.error); mpc_input_unmark(i); - MPC_SUCCESS(mpc_stack_merger_out(stk, st-1, p->data.repeat.f)); + MPC_SUCCESS(mpc_stack_merger_out(stk, st, p->data.repeat.f)); } } } diff --git a/tests/core.c b/tests/core.c index 516e2ae..de4a3e6 100644 --- a/tests/core.c +++ b/tests/core.c @@ -85,8 +85,38 @@ void test_strip(void) { } -void suite_core(void) { - pt_add_test(test_ident, "Test Ident", "Suite Core"); - pt_add_test(test_maths, "Test Maths", "Suite Core"); - pt_add_test(test_strip, "Test Strip", "Suite Core"); +void test_repeat(void) { + + int success; + mpc_result_t r; + mpc_parser_t *p = mpc_count(3, mpcf_strfold, mpc_digit(), free); + + success = mpc_parse("test", "046", p, &r); + PT_ASSERT(success); + PT_ASSERT_STR_EQ(r.output, "046"); + free(r.output); + + success = mpc_parse("test", "046aa", p, &r); + PT_ASSERT(success); + PT_ASSERT_STR_EQ(r.output, "046"); + free(r.output); + + success = mpc_parse("test", "04632", p, &r); + PT_ASSERT(success); + PT_ASSERT_STR_EQ(r.output, "046"); + free(r.output); + + success = mpc_parse("test", "04", p, &r); + PT_ASSERT(!success); + mpc_err_delete(r.error); + + mpc_delete(p); + +} + +void suite_core(void) { + pt_add_test(test_ident, "Test Ident", "Suite Core"); + pt_add_test(test_maths, "Test Maths", "Suite Core"); + pt_add_test(test_strip, "Test Strip", "Suite Core"); + pt_add_test(test_repeat, "Test Repeat", "Suite Core"); } From bbd6d4309449c684657c45d9a68a51853797df0d Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Fri, 28 Aug 2015 19:22:01 +0100 Subject: [PATCH 18/49] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e2bff1..b9c84a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mpc", - "version": "0.8.5", + "version": "0.8.6", "repo": "orangeduck/mpc", "description": "A Parser Combinator library for C", "keywords": ["parser", "combinator", "library", "c", "mpc"], From af81180fa94ea9696d09d59475d70112a6e03c24 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 7 Nov 2015 12:51:23 +0000 Subject: [PATCH 19/49] Minor performance tweak --- mpc.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/mpc.c b/mpc.c index 26985f5..cef0683 100644 --- a/mpc.c +++ b/mpc.c @@ -748,18 +748,23 @@ typedef struct { } mpc_stack_t; +enum { + MPC_STACK_MIN = 128 +}; + static mpc_stack_t *mpc_stack_new(const char *filename) { mpc_stack_t *s = malloc(sizeof(mpc_stack_t)); s->parsers_num = 0; - s->parsers_slots = 0; - s->parsers = NULL; - s->states = NULL; + s->parsers_slots = MPC_STACK_MIN; + s->parsers = malloc(sizeof(mpc_parser_t*) * MPC_STACK_MIN); + s->states = malloc(sizeof(int) * MPC_STACK_MIN); s->results_num = 0; - s->results_slots = 0; - s->results = NULL; - s->returns = NULL; + s->results_slots = MPC_STACK_MIN; + + s->results = malloc(sizeof(mpc_result_t) * MPC_STACK_MIN); + s->returns = malloc(sizeof(int) * MPC_STACK_MIN); s->err = mpc_err_fail(filename, mpc_state_invalid(), "Unknown Error"); @@ -801,15 +806,18 @@ static void mpc_stack_set_state(mpc_stack_t *s, int x) { static void mpc_stack_parsers_reserve_more(mpc_stack_t *s) { if (s->parsers_num > s->parsers_slots) { - s->parsers_slots = ceil((s->parsers_slots+1) * 1.5); + s->parsers_slots = s->parsers_num + s->parsers_num / 2; s->parsers = realloc(s->parsers, sizeof(mpc_parser_t*) * s->parsers_slots); s->states = realloc(s->states, sizeof(int) * s->parsers_slots); } } static void mpc_stack_parsers_reserve_less(mpc_stack_t *s) { - if (s->parsers_slots > pow(s->parsers_num+1, 1.5)) { - s->parsers_slots = floor((s->parsers_slots-1) * (1.0/1.5)); + if (s->parsers_slots > s->parsers_num + s->parsers_num / 2 + && s->parsers_slots > MPC_STACK_MIN) { + s->parsers_slots = + s->parsers_num > MPC_STACK_MIN ? + s->parsers_num : MPC_STACK_MIN; s->parsers = realloc(s->parsers, sizeof(mpc_parser_t*) * s->parsers_slots); s->states = realloc(s->states, sizeof(int) * s->parsers_slots); } @@ -854,15 +862,18 @@ static mpc_result_t mpc_result_out(mpc_val_t *x) { static void mpc_stack_results_reserve_more(mpc_stack_t *s) { if (s->results_num > s->results_slots) { - s->results_slots = ceil((s->results_slots + 1) * 1.5); + s->results_slots = s->results_num + s->results_num / 2; s->results = realloc(s->results, sizeof(mpc_result_t) * s->results_slots); s->returns = realloc(s->returns, sizeof(int) * s->results_slots); } } static void mpc_stack_results_reserve_less(mpc_stack_t *s) { - if ( s->results_slots > pow(s->results_num+1, 1.5)) { - s->results_slots = floor((s->results_slots-1) * (1.0/1.5)); + if (s->results_slots > s->results_num + s->results_num / 2 + && s->results_slots > MPC_STACK_MIN) { + s->results_slots = + s->results_num > MPC_STACK_MIN ? + s->results_num : MPC_STACK_MIN; s->results = realloc(s->results, sizeof(mpc_result_t) * s->results_slots); s->returns = realloc(s->returns, sizeof(int) * s->results_slots); } From 4472dd4363b585b9a1c993fd7c250ad699d1671a Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 7 Nov 2015 16:57:09 +0000 Subject: [PATCH 20/49] Added basic optimise function for parsers. --- .gitignore | 9 +- README.md | 29 + examples/doge.c | 8 +- examples/lispy.c | 10 +- examples/so_c.doge | 2009 ++++++++++++++++++++++++++++++++++++++++++++ mpc.c | 242 +++++- mpc.h | 5 +- 7 files changed, 2296 insertions(+), 16 deletions(-) create mode 100644 examples/so_c.doge diff --git a/.gitignore b/.gitignore index 14a8995..40be4fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ *.exe *.dSYM test -doge -lispy -maths -smallc +examples/doge +examples/lispy +examples/maths +examples/smallc +examples/foobar diff --git a/README.md b/README.md index c2d6192..b470778 100644 --- a/README.md +++ b/README.md @@ -786,6 +786,35 @@ _mpc_ provides some automatic generation of error messages. These can be enhance :0:3: error: expected one or more of 'a' or 'd' at 'k' ``` +Misc +==== + +Here are some other misc functions that mpc provides. These functions are susceptible to change between versions so use them with some care. + +* * * + +```c +void mpc_print(mpc_parser_t *p); +``` + +Prints out a parser in some weird format. This is generally used for debugging so don't expect to be able to understand the output right away without looking at the source code a little bit. + +* * * + +```c +void mpc_stats(mpc_parser_t *p); +``` + +Prints out some basic stats about a parser. Again used for debugging and optimisation. + +* * * + +```c +void mpc_optimise(mpc_parser_t *p); +``` + +Performs some basic optimisations on a parser to reduce it's size and increase its running speed. + Limitations & FAQ ================= diff --git a/examples/doge.c b/examples/doge.c index 597eebc..4adfb51 100644 --- a/examples/doge.c +++ b/examples/doge.c @@ -1,6 +1,8 @@ #include "../mpc.h" int main(int argc, char **argv) { + + mpc_result_t r; mpc_parser_t* Adjective = mpc_new("adjective"); mpc_parser_t* Noun = mpc_new("noun"); @@ -13,10 +15,9 @@ int main(int argc, char **argv) { " phrase : ; " " doge : /^/ * /$/; ", Adjective, Noun, Phrase, Doge, NULL); - + if (argc > 1) { - mpc_result_t r; if (mpc_parse_contents(argv[1], Doge, &r)) { mpc_ast_print(r.output); mpc_ast_delete(r.output); @@ -24,10 +25,9 @@ int main(int argc, char **argv) { mpc_err_print(r.error); mpc_err_delete(r.error); } - + } else { - mpc_result_t r; if (mpc_parse_pipe("", stdin, Doge, &r)) { mpc_ast_print(r.output); mpc_ast_delete(r.output); diff --git a/examples/lispy.c b/examples/lispy.c index 982bf0b..a3aa093 100644 --- a/examples/lispy.c +++ b/examples/lispy.c @@ -2,6 +2,8 @@ int main(int argc, char **argv) { + mpc_result_t r; + mpc_parser_t* Number = mpc_new("number"); mpc_parser_t* Symbol = mpc_new("symbol"); mpc_parser_t* String = mpc_new("string"); @@ -22,10 +24,9 @@ int main(int argc, char **argv) { " | | | ; " " lispy : /^/ * /$/ ; ", Number, Symbol, String, Comment, Sexpr, Qexpr, Expr, Lispy, NULL); - + if (argc > 1) { - - mpc_result_t r; + if (mpc_parse_contents(argv[1], Lispy, &r)) { mpc_ast_print(r.output); mpc_ast_delete(r.output); @@ -33,10 +34,9 @@ int main(int argc, char **argv) { mpc_err_print(r.error); mpc_err_delete(r.error); } - + } else { - mpc_result_t r; if (mpc_parse_pipe("", stdin, Lispy, &r)) { mpc_ast_print(r.output); mpc_ast_delete(r.output); diff --git a/examples/so_c.doge b/examples/so_c.doge new file mode 100644 index 0000000..0ef7f3c --- /dev/null +++ b/examples/so_c.doge @@ -0,0 +1,2009 @@ +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c +so c so c so c so c so c so c so c so c so c + diff --git a/mpc.c b/mpc.c index cef0683..1dc4219 100644 --- a/mpc.c +++ b/mpc.c @@ -749,7 +749,7 @@ typedef struct { } mpc_stack_t; enum { - MPC_STACK_MIN = 128 + MPC_STACK_MIN = 256 }; static mpc_stack_t *mpc_stack_new(const char *filename) { @@ -1538,7 +1538,7 @@ mpc_parser_t *mpc_noneof(const char *s) { p->type = MPC_TYPE_NONEOF; p->data.string.x = malloc(strlen(s) + 1); strcpy(p->data.string.x, s); - return mpc_expectf(p, "one of '%s'", s); + return mpc_expectf(p, "none of '%s'", s); } @@ -2059,6 +2059,12 @@ mpc_parser_t *mpc_re(const char *re) { RegexEnclose = mpc_whole(mpc_predictive(Regex), (mpc_dtor_t)mpc_delete); + mpc_optimise(Regex); + mpc_optimise(Term); + mpc_optimise(Factor); + mpc_optimise(Base); + mpc_optimise(Range); + if(!mpc_parse("", re, RegexEnclose, &r)) { err_msg = mpc_err_string(r.error); err_out = mpc_failf("Invalid Regex: %s", err_msg); @@ -3001,6 +3007,12 @@ mpc_parser_t *mpca_grammar_st(const char *grammar, mpca_grammar_st_t *st) { mpc_tok_parens(Grammar, mpc_soft_delete) )); + mpc_optimise(GrammarTotal); + mpc_optimise(Grammar); + mpc_optimise(Factor); + mpc_optimise(Term); + mpc_optimise(Base); + if(!mpc_parse("", grammar, GrammarTotal, &r)) { err_msg = mpc_err_string(r.error); err_out = mpc_failf("Invalid Grammar: %s", err_msg); @@ -3091,12 +3103,14 @@ static mpc_val_t *mpca_stmt_list_apply_to(mpc_val_t *x, void *s) { left = mpca_grammar_find_parser(stmt->ident, st); if (st->flags & MPCA_LANG_PREDICTIVE) { stmt->grammar = mpc_predictive(stmt->grammar); } if (stmt->name) { stmt->grammar = mpc_expect(stmt->grammar, stmt->name); } + mpc_optimise(stmt->grammar); mpc_define(left, stmt->grammar); free(stmt->ident); free(stmt->name); free(stmt); stmts++; } + free(x); return NULL; @@ -3153,6 +3167,12 @@ static mpc_err_t *mpca_lang_st(mpc_input_t *i, mpca_grammar_st_t *st) { mpc_tok_parens(Grammar, mpc_soft_delete) )); + mpc_optimise(Lang); + mpc_optimise(Stmt); + mpc_optimise(Grammar); + mpc_optimise(Term); + mpc_optimise(Factor); + mpc_optimise(Base); if (!mpc_parse_input(i, Lang, &r)) { e = r.error; @@ -3264,3 +3284,221 @@ mpc_err_t *mpca_lang_contents(int flags, const char *filename, ...) { return err; } + +static int mpc_nodecount_unretained(mpc_parser_t* p, int force) { + + int i, total; + + if (p->retained && !force) { return 0; } + + if (p->type == MPC_TYPE_EXPECT) { return 1 + mpc_nodecount_unretained(p->data.expect.x, 0); } + + if (p->type == MPC_TYPE_APPLY) { return 1 + mpc_nodecount_unretained(p->data.apply.x, 0); } + if (p->type == MPC_TYPE_APPLY_TO) { return 1 + mpc_nodecount_unretained(p->data.apply_to.x, 0); } + if (p->type == MPC_TYPE_PREDICT) { return 1 + mpc_nodecount_unretained(p->data.predict.x, 0); } + + if (p->type == MPC_TYPE_NOT) { return 1 + mpc_nodecount_unretained(p->data.not.x, 0); } + if (p->type == MPC_TYPE_MAYBE) { return 1 + mpc_nodecount_unretained(p->data.not.x, 0); } + + if (p->type == MPC_TYPE_MANY) { return 1 + mpc_nodecount_unretained(p->data.repeat.x, 0); } + if (p->type == MPC_TYPE_MANY1) { return 1 + mpc_nodecount_unretained(p->data.repeat.x, 0); } + if (p->type == MPC_TYPE_COUNT) { return 1 + mpc_nodecount_unretained(p->data.repeat.x, 0); } + + if (p->type == MPC_TYPE_OR) { + total = 0; + for(i = 0; i < p->data.or.n; i++) { + total += mpc_nodecount_unretained(p->data.or.xs[i], 0); + } + return total; + } + + if (p->type == MPC_TYPE_AND) { + total = 0; + for(i = 0; i < p->data.and.n; i++) { + total += mpc_nodecount_unretained(p->data.and.xs[i], 0); + } + return total; + } + + return 1; + +} + +void mpc_stats(mpc_parser_t* p) { + printf("Stats\n"); + printf("=====\n"); + printf("Node Count: %i\n", mpc_nodecount_unretained(p, 1)); +} + +static void mpc_optimise_unretained(mpc_parser_t *p, int force) { + + int i, n, m; + mpc_parser_t *t; + mpc_parser_t swp; + + if (p->retained && !force) { return; } + + /* Optimise Subexpressions */ + + if (p->type == MPC_TYPE_EXPECT) { mpc_optimise_unretained(p->data.expect.x, 0); } + if (p->type == MPC_TYPE_APPLY) { mpc_optimise_unretained(p->data.apply.x, 0); } + if (p->type == MPC_TYPE_APPLY_TO) { mpc_optimise_unretained(p->data.apply_to.x, 0); } + if (p->type == MPC_TYPE_PREDICT) { mpc_optimise_unretained(p->data.predict.x, 0); } + if (p->type == MPC_TYPE_NOT) { mpc_optimise_unretained(p->data.not.x, 0); } + if (p->type == MPC_TYPE_MAYBE) { mpc_optimise_unretained(p->data.not.x, 0); } + if (p->type == MPC_TYPE_MANY) { mpc_optimise_unretained(p->data.repeat.x, 0); } + if (p->type == MPC_TYPE_MANY1) { mpc_optimise_unretained(p->data.repeat.x, 0); } + if (p->type == MPC_TYPE_COUNT) { mpc_optimise_unretained(p->data.repeat.x, 0); } + + if (p->type == MPC_TYPE_OR) { + for(i = 0; i < p->data.or.n; i++) { + mpc_optimise_unretained(p->data.or.xs[i], 0); + } + } + + if (p->type == MPC_TYPE_AND) { + for(i = 0; i < p->data.and.n; i++) { + mpc_optimise_unretained(p->data.and.xs[i], 0); + } + } + + /* Perform optimisations */ + + while (1) { + + /* Merge rhs `or` */ + if (p->type == MPC_TYPE_OR + && p->data.or.xs[p->data.or.n-1]->type == MPC_TYPE_OR + && !p->data.or.xs[p->data.or.n-1]->retained) { + t = p->data.or.xs[p->data.or.n-1]; + n = p->data.or.n; m = t->data.or.n; + p->data.or.n = n + m - 1; + p->data.or.xs = realloc(p->data.or.xs, sizeof(mpc_parser_t*) * (n + m -1)); + memmove(p->data.or.xs + n - 1, t->data.or.xs, m * sizeof(mpc_parser_t*)); + free(t->data.or.xs); free(t->name); free(t); + continue; + } + + /* Merge lhs `or` */ + if (p->type == MPC_TYPE_OR + && p->data.or.xs[0]->type == MPC_TYPE_OR + && !p->data.or.xs[0]->retained) { + t = p->data.or.xs[0]; + n = p->data.or.n; m = t->data.or.n; + p->data.or.n = n + m - 1; + p->data.or.xs = realloc(p->data.or.xs, sizeof(mpc_parser_t*) * (n + m -1)); + memmove(p->data.or.xs + m, t->data.or.xs + 1, n * sizeof(mpc_parser_t*)); + memmove(p->data.or.xs, t->data.or.xs, m * sizeof(mpc_parser_t*)); + free(t->data.or.xs); free(t->name); free(t); + continue; + } + + /* Remove ast `pass` */ + if (p->type == MPC_TYPE_AND + && p->data.and.n == 2 + && p->data.and.xs[0]->type == MPC_TYPE_PASS + && !p->data.and.xs[0]->retained + && p->data.and.f == mpcf_fold_ast) { + memcpy(&swp, p->data.and.xs[1], sizeof(mpc_parser_t)); + mpc_delete(p->data.and.xs[0]); + free(p->data.and.xs); free(p->data.and.dxs); + memcpy(p, &swp, sizeof(mpc_parser_t)); + continue; + } + + /* Merge ast lhs `and` */ + if (p->type == MPC_TYPE_AND + && p->data.and.f == mpcf_fold_ast + && p->data.and.xs[0]->type == MPC_TYPE_AND + && !p->data.and.xs[0]->retained + && p->data.and.xs[0]->data.and.f == mpcf_fold_ast) { + t = p->data.and.xs[0]; + n = p->data.and.n; m = t->data.and.n; + p->data.and.n = n + m - 1; + p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + memmove(p->data.and.xs + m, p->data.and.xs + 1, (n - 1) * sizeof(mpc_parser_t*)); + memmove(p->data.and.xs, t->data.and.xs, m * sizeof(mpc_parser_t*)); + memmove(p->data.and.dxs + m, p->data.and.dxs + 1, (n - 1) * sizeof(mpc_dtor_t)); + memmove(p->data.and.dxs, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); + continue; + } + + /* Merge ast rhs `and` */ + if (p->type == MPC_TYPE_AND + && p->data.and.f == mpcf_fold_ast + && p->data.and.xs[p->data.and.n-1]->type == MPC_TYPE_AND + && !p->data.and.xs[p->data.and.n-1]->retained + && p->data.and.xs[p->data.and.n-1]->data.and.f == mpcf_fold_ast) { + t = p->data.and.xs[p->data.and.n-1]; + n = p->data.and.n; m = t->data.and.n; + p->data.and.n = n + m - 1; + p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + memmove(p->data.and.xs + n - 1, t->data.and.xs, m * sizeof(mpc_parser_t*)); + memmove(p->data.and.dxs + n - 1, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); + continue; + } + + /* Remove re `lift` */ + if (p->type == MPC_TYPE_AND + && p->data.and.n == 2 + && p->data.and.xs[0]->type == MPC_TYPE_LIFT + && p->data.and.xs[0]->data.lift.lf == mpcf_ctor_str + && !p->data.and.xs[0]->retained + && p->data.and.f == mpcf_strfold) { + memcpy(&swp, p->data.and.xs[1], sizeof(mpc_parser_t)); + mpc_delete(p->data.and.xs[0]); + free(p->data.and.xs); free(p->data.and.dxs); + memcpy(p, &swp, sizeof(mpc_parser_t)); + continue; + } + + /* Merge re lhs `and` */ + if (p->type == MPC_TYPE_AND + && p->data.and.f == mpcf_strfold + && p->data.and.xs[0]->type == MPC_TYPE_AND + && !p->data.and.xs[0]->retained + && p->data.and.xs[0]->data.and.f == mpcf_strfold) { + t = p->data.and.xs[0]; + n = p->data.and.n; m = t->data.and.n; + p->data.and.n = n + m - 1; + p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + memmove(p->data.and.xs + m, p->data.and.xs + 1, (n - 1) * sizeof(mpc_parser_t*)); + memmove(p->data.and.xs, t->data.and.xs, m * sizeof(mpc_parser_t*)); + memmove(p->data.and.dxs + m, p->data.and.dxs + 1, (n - 1) * sizeof(mpc_dtor_t)); + memmove(p->data.and.dxs, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); + continue; + } + + /* Merge re rhs `and` */ + if (p->type == MPC_TYPE_AND + && p->data.and.f == mpcf_strfold + && p->data.and.xs[p->data.and.n-1]->type == MPC_TYPE_AND + && !p->data.and.xs[p->data.and.n-1]->retained + && p->data.and.xs[p->data.and.n-1]->data.and.f == mpcf_strfold) { + t = p->data.and.xs[p->data.and.n-1]; + n = p->data.and.n; m = t->data.and.n; + p->data.and.n = n + m - 1; + p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + memmove(p->data.and.xs + n - 1, t->data.and.xs, m * sizeof(mpc_parser_t*)); + memmove(p->data.and.dxs + n - 1, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); + continue; + } + + return; + + } + +} + +void mpc_optimise(mpc_parser_t *p) { + mpc_optimise_unretained(p, 1); +} + diff --git a/mpc.h b/mpc.h index e75685c..a408d09 100644 --- a/mpc.h +++ b/mpc.h @@ -314,10 +314,13 @@ mpc_err_t *mpca_lang_pipe(int flags, FILE *f, ...); mpc_err_t *mpca_lang_contents(int flags, const char *filename, ...); /* -** Debug & Testing +** Misc */ + void mpc_print(mpc_parser_t *p); +void mpc_optimise(mpc_parser_t *p); +void mpc_stats(mpc_parser_t *p); int mpc_test_pass(mpc_parser_t *p, const char *s, const void *d, int(*tester)(const void*, const void*), From 2d111680df8eaf943d8722f60f602d9c77c06e43 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 7 Nov 2015 16:58:47 +0000 Subject: [PATCH 21/49] update version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9c84a5..f398f3b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mpc", - "version": "0.8.6", + "version": "0.8.7", "repo": "orangeduck/mpc", "description": "A Parser Combinator library for C", "keywords": ["parser", "combinator", "library", "c", "mpc"], From 3c266180c4984f1d5aba35e4e3ecc5f4776bc398 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 7 Nov 2015 17:34:47 +0000 Subject: [PATCH 22/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b470778..7321a41 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Micro Parser Combinators ======================== -Version 0.8.6 +Version 0.8.7 About From 4932c86ec7afc2a0c0cc1f2e1942834ebd77d8aa Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Mon, 9 Nov 2015 12:06:13 +0000 Subject: [PATCH 23/49] Fixed bug in optimisation pass. --- Makefile | 2 +- mpc.c | 30 ++++++++++++++++-------------- tests/grammar.c | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 9df01fc..69fe65e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc STND=-ansi -CFLAGS = $(STND) -pedantic -O3 -g -Werror -Wall -Wextra -Wformat=2 -Wshadow \ +CFLAGS = $(STND) -pedantic -O0 -g -Wall -Werror -Wextra -Wformat=2 -Wshadow \ -Wno-long-long -Wno-overlength-strings -Wno-format-nonliteral -Wcast-align \ -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wredundant-decls \ -Wnested-externs -Wmissing-include-dirs -Wswitch-default diff --git a/mpc.c b/mpc.c index 1dc4219..62024f4 100644 --- a/mpc.c +++ b/mpc.c @@ -2059,6 +2059,7 @@ mpc_parser_t *mpc_re(const char *re) { RegexEnclose = mpc_whole(mpc_predictive(Regex), (mpc_dtor_t)mpc_delete); + mpc_optimise(RegexEnclose); mpc_optimise(Regex); mpc_optimise(Term); mpc_optimise(Factor); @@ -2073,8 +2074,9 @@ mpc_parser_t *mpc_re(const char *re) { r.output = err_out; } - mpc_delete(RegexEnclose); - mpc_cleanup(5, Regex, Term, Factor, Base, Range); + mpc_cleanup(6, RegexEnclose, Regex, Term, Factor, Base, Range); + + mpc_optimise(r.output); return r.output; @@ -3023,6 +3025,8 @@ mpc_parser_t *mpca_grammar_st(const char *grammar, mpca_grammar_st_t *st) { mpc_cleanup(5, GrammarTotal, Grammar, Term, Factor, Base); + mpc_optimise(r.output); + return (st->flags & MPCA_LANG_PREDICTIVE) ? mpc_predictive(r.output) : r.output; } @@ -3415,12 +3419,11 @@ static void mpc_optimise_unretained(mpc_parser_t *p, int force) { t = p->data.and.xs[0]; n = p->data.and.n; m = t->data.and.n; p->data.and.n = n + m - 1; - p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); - p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m - 1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m - 1 - 1)); memmove(p->data.and.xs + m, p->data.and.xs + 1, (n - 1) * sizeof(mpc_parser_t*)); memmove(p->data.and.xs, t->data.and.xs, m * sizeof(mpc_parser_t*)); - memmove(p->data.and.dxs + m, p->data.and.dxs + 1, (n - 1) * sizeof(mpc_dtor_t)); - memmove(p->data.and.dxs, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + for (i = 0; i < p->data.and.n-1; i++) { p->data.and.dxs[i] = (mpc_dtor_t)mpc_ast_delete; } free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); continue; } @@ -3435,9 +3438,9 @@ static void mpc_optimise_unretained(mpc_parser_t *p, int force) { n = p->data.and.n; m = t->data.and.n; p->data.and.n = n + m - 1; p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); - p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m - 1 - 1)); memmove(p->data.and.xs + n - 1, t->data.and.xs, m * sizeof(mpc_parser_t*)); - memmove(p->data.and.dxs + n - 1, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + for (i = 0; i < p->data.and.n-1; i++) { p->data.and.dxs[i] = (mpc_dtor_t)mpc_ast_delete; } free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); continue; } @@ -3465,12 +3468,11 @@ static void mpc_optimise_unretained(mpc_parser_t *p, int force) { t = p->data.and.xs[0]; n = p->data.and.n; m = t->data.and.n; p->data.and.n = n + m - 1; - p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); - p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m - 1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m - 1 - 1)); memmove(p->data.and.xs + m, p->data.and.xs + 1, (n - 1) * sizeof(mpc_parser_t*)); memmove(p->data.and.xs, t->data.and.xs, m * sizeof(mpc_parser_t*)); - memmove(p->data.and.dxs + m, p->data.and.dxs + 1, (n - 1) * sizeof(mpc_dtor_t)); - memmove(p->data.and.dxs, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + for (i = 0; i < p->data.and.n-1; i++) { p->data.and.dxs[i] = free; } free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); continue; } @@ -3485,9 +3487,9 @@ static void mpc_optimise_unretained(mpc_parser_t *p, int force) { n = p->data.and.n; m = t->data.and.n; p->data.and.n = n + m - 1; p->data.and.xs = realloc(p->data.and.xs, sizeof(mpc_parser_t*) * (n + m -1)); - p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m -1)); + p->data.and.dxs = realloc(p->data.and.dxs, sizeof(mpc_dtor_t) * (n + m - 1 - 1)); memmove(p->data.and.xs + n - 1, t->data.and.xs, m * sizeof(mpc_parser_t*)); - memmove(p->data.and.dxs + n - 1, t->data.and.dxs, m * sizeof(mpc_dtor_t)); + for (i = 0; i < p->data.and.n-1; i++) { p->data.and.dxs[i] = free; } free(t->data.and.xs); free(t->data.and.dxs); free(t->name); free(t); continue; } diff --git a/tests/grammar.c b/tests/grammar.c index 562b0d1..b1cd2e5 100644 --- a/tests/grammar.c +++ b/tests/grammar.c @@ -91,8 +91,46 @@ void test_language_file(void) { } +void test_doge(void) { + + mpc_ast_t *t0; + mpc_parser_t* Adjective = mpc_new("adjective"); + mpc_parser_t* Noun = mpc_new("noun"); + mpc_parser_t* Phrase = mpc_new("phrase"); + mpc_parser_t* Doge = mpc_new("doge"); + + mpca_lang(MPCA_LANG_DEFAULT, + " adjective : \"wow\" | \"many\" | \"so\" | \"such\"; " + " noun : \"lisp\" | \"language\" | \"c\" | \"book\" | \"build\"; " + " phrase : ; " + " doge : /^/ * /$/; ", + Adjective, Noun, Phrase, Doge, NULL); + + t0 = + mpc_ast_build(4, ">", + mpc_ast_new("regex", ""), + mpc_ast_build(2, "phrase|>", + mpc_ast_new("adjective|string", "so"), + mpc_ast_new("noun|string", "c")), + mpc_ast_build(2, "phrase|>", + mpc_ast_new("adjective|string", "so"), + mpc_ast_new("noun|string", "c")), + mpc_ast_new("regex", "") + ); + + PT_ASSERT(mpc_test_pass(Doge, "so c so c", t0, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); + + PT_ASSERT(mpc_test_fail(Doge, "so a so c", t0, (int(*)(const void*,const void*))mpc_ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(const void*))mpc_ast_print)); + + mpc_ast_delete(t0); + + mpc_cleanup(4, Adjective, Noun, Phrase, Doge); + +} + void suite_grammar(void) { pt_add_test(test_grammar, "Test Grammar", "Suite Grammar"); pt_add_test(test_language, "Test Language", "Suite Grammar"); pt_add_test(test_language_file, "Test Language File", "Suite Grammar"); + pt_add_test(test_doge, "Test Doge", "Suite Grammar"); } From f8c9429a1072e4d189c76e60312daae6d529b053 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Mon, 9 Nov 2015 13:33:06 +0000 Subject: [PATCH 24/49] Faster strfold function. --- mpc.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mpc.c b/mpc.c index 62024f4..d3934da 100644 --- a/mpc.c +++ b/mpc.c @@ -2301,14 +2301,19 @@ 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) { 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]); - free(xs[i]); + size_t l; + + if (n == 0) { return calloc(1, 1); } + + for (i = 0; i < n; i++) { l += strlen(xs[i]); } + + xs[0] = realloc(xs[0], l + 1); + + for (i = 1; i < n; i++) { + strcat(xs[0], xs[i]); free(xs[i]); } - return x; + + return xs[0]; } mpc_val_t *mpcf_maths(int n, mpc_val_t **xs) { From 613fc2672903bec1d10c60b434664689a6058532 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Mon, 9 Nov 2015 13:34:39 +0000 Subject: [PATCH 25/49] fixed bug. Reenabled O3. --- Makefile | 2 +- mpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 69fe65e..4f3cca0 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc STND=-ansi -CFLAGS = $(STND) -pedantic -O0 -g -Wall -Werror -Wextra -Wformat=2 -Wshadow \ +CFLAGS = $(STND) -pedantic -O3 -g -Wall -Werror -Wextra -Wformat=2 -Wshadow \ -Wno-long-long -Wno-overlength-strings -Wno-format-nonliteral -Wcast-align \ -Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wredundant-decls \ -Wnested-externs -Wmissing-include-dirs -Wswitch-default diff --git a/mpc.c b/mpc.c index d3934da..0bed4c1 100644 --- a/mpc.c +++ b/mpc.c @@ -2301,7 +2301,7 @@ 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) { int i; - size_t l; + size_t l = 0; if (n == 0) { return calloc(1, 1); } From 991a6e4156fe9c2da35e846eb2c9edee1a437a96 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Mon, 9 Nov 2015 15:02:38 +0000 Subject: [PATCH 26/49] Small optimisation --- mpc.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/mpc.c b/mpc.c index 0bed4c1..5770441 100644 --- a/mpc.c +++ b/mpc.c @@ -324,6 +324,7 @@ typedef struct { FILE *file; int backtrack; + int marks_slots; int marks_num; mpc_state_t* marks; char* lasts; @@ -332,6 +333,10 @@ typedef struct { } mpc_input_t; +enum { + MPC_INPUT_MARKS_MIN = 32 +}; + static mpc_input_t *mpc_input_new_string(const char *filename, const char *string) { mpc_input_t *i = malloc(sizeof(mpc_input_t)); @@ -349,8 +354,9 @@ static mpc_input_t *mpc_input_new_string(const char *filename, const char *strin i->backtrack = 1; i->marks_num = 0; - i->marks = NULL; - i->lasts = NULL; + i->marks_slots = MPC_INPUT_MARKS_MIN; + i->marks = malloc(sizeof(mpc_state_t) * i->marks_slots); + i->lasts = malloc(sizeof(char) * i->marks_slots); i->last = '\0'; @@ -373,8 +379,9 @@ static mpc_input_t *mpc_input_new_pipe(const char *filename, FILE *pipe) { i->backtrack = 1; i->marks_num = 0; - i->marks = NULL; - i->lasts = NULL; + i->marks_slots = MPC_INPUT_MARKS_MIN; + i->marks = malloc(sizeof(mpc_state_t) * i->marks_slots); + i->lasts = malloc(sizeof(char) * i->marks_slots); i->last = '\0'; @@ -397,8 +404,9 @@ static mpc_input_t *mpc_input_new_file(const char *filename, FILE *file) { i->backtrack = 1; i->marks_num = 0; - i->marks = NULL; - i->lasts = NULL; + i->marks_slots = MPC_INPUT_MARKS_MIN; + i->marks = malloc(sizeof(mpc_state_t) * i->marks_slots); + i->lasts = malloc(sizeof(char) * i->marks_slots); i->last = '\0'; @@ -425,8 +433,13 @@ static void mpc_input_mark(mpc_input_t *i) { if (i->backtrack < 1) { return; } i->marks_num++; - i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_num); - i->lasts = realloc(i->lasts, sizeof(char) * i->marks_num); + + if (i->marks_num > i->marks_slots) { + i->marks_slots = i->marks_num + i->marks_num / 2; + i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_slots); + i->lasts = realloc(i->lasts, sizeof(char) * i->marks_slots); + } + i->marks[i->marks_num-1] = i->state; i->lasts[i->marks_num-1] = i->last; @@ -441,8 +454,15 @@ static void mpc_input_unmark(mpc_input_t *i) { if (i->backtrack < 1) { return; } i->marks_num--; - i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_num); - i->lasts = realloc(i->lasts, sizeof(char) * i->marks_num); + + if (i->marks_slots > i->marks_num + i->marks_num / 2 + && i->marks_slots > MPC_INPUT_MARKS_MIN) { + i->marks_slots = + i->marks_num > MPC_INPUT_MARKS_MIN ? + i->marks_num : MPC_INPUT_MARKS_MIN; + i->marks = realloc(i->marks, sizeof(mpc_state_t) * i->marks_slots); + i->lasts = realloc(i->lasts, sizeof(char) * i->marks_slots); + } if (i->type == MPC_INPUT_PIPE && i->marks_num == 0) { free(i->buffer); From 31889d86c3834021922d6d95fbce902893dab793 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Tue, 10 Nov 2015 20:25:39 +0000 Subject: [PATCH 27/49] Switched parsing to use C function stack --- mpc.c | 646 +++++++++++++++++++--------------------------------------- 1 file changed, 211 insertions(+), 435 deletions(-) diff --git a/mpc.c b/mpc.c index 5770441..2ed905b 100644 --- a/mpc.c +++ b/mpc.c @@ -748,225 +748,6 @@ struct mpc_parser_t { mpc_pdata_t data; }; -/* -** Stack Type -*/ - -typedef struct { - - int parsers_num; - int parsers_slots; - mpc_parser_t **parsers; - int *states; - - int results_num; - int results_slots; - mpc_result_t *results; - int *returns; - - mpc_err_t *err; - -} mpc_stack_t; - -enum { - MPC_STACK_MIN = 256 -}; - -static mpc_stack_t *mpc_stack_new(const char *filename) { - mpc_stack_t *s = malloc(sizeof(mpc_stack_t)); - - s->parsers_num = 0; - s->parsers_slots = MPC_STACK_MIN; - s->parsers = malloc(sizeof(mpc_parser_t*) * MPC_STACK_MIN); - s->states = malloc(sizeof(int) * MPC_STACK_MIN); - - s->results_num = 0; - s->results_slots = MPC_STACK_MIN; - - s->results = malloc(sizeof(mpc_result_t) * MPC_STACK_MIN); - s->returns = malloc(sizeof(int) * MPC_STACK_MIN); - - s->err = mpc_err_fail(filename, mpc_state_invalid(), "Unknown Error"); - - return s; -} - -static void mpc_stack_err(mpc_stack_t *s, mpc_err_t* e) { - mpc_err_t *errs[2]; - errs[0] = s->err; - errs[1] = e; - s->err = mpc_err_or(errs, 2); -} - -static int mpc_stack_terminate(mpc_stack_t *s, mpc_result_t *r) { - int success = s->returns[0]; - - if (success) { - r->output = s->results[0].output; - mpc_err_delete(s->err); - } else { - mpc_stack_err(s, s->results[0].error); - r->error = s->err; - } - - free(s->parsers); - free(s->states); - free(s->results); - free(s->returns); - free(s); - - return success; -} - -/* Stack Parser Stuff */ - -static void mpc_stack_set_state(mpc_stack_t *s, int x) { - s->states[s->parsers_num-1] = x; -} - -static void mpc_stack_parsers_reserve_more(mpc_stack_t *s) { - if (s->parsers_num > s->parsers_slots) { - s->parsers_slots = s->parsers_num + s->parsers_num / 2; - s->parsers = realloc(s->parsers, sizeof(mpc_parser_t*) * s->parsers_slots); - s->states = realloc(s->states, sizeof(int) * s->parsers_slots); - } -} - -static void mpc_stack_parsers_reserve_less(mpc_stack_t *s) { - if (s->parsers_slots > s->parsers_num + s->parsers_num / 2 - && s->parsers_slots > MPC_STACK_MIN) { - s->parsers_slots = - s->parsers_num > MPC_STACK_MIN ? - s->parsers_num : MPC_STACK_MIN; - s->parsers = realloc(s->parsers, sizeof(mpc_parser_t*) * s->parsers_slots); - s->states = realloc(s->states, sizeof(int) * s->parsers_slots); - } -} - -static void mpc_stack_pushp(mpc_stack_t *s, mpc_parser_t *p) { - s->parsers_num++; - mpc_stack_parsers_reserve_more(s); - s->parsers[s->parsers_num-1] = p; - s->states[s->parsers_num-1] = 0; -} - -static void mpc_stack_popp(mpc_stack_t *s, mpc_parser_t **p, int *st) { - *p = s->parsers[s->parsers_num-1]; - *st = s->states[s->parsers_num-1]; - s->parsers_num--; - mpc_stack_parsers_reserve_less(s); -} - -static void mpc_stack_peepp(mpc_stack_t *s, mpc_parser_t **p, int *st) { - *p = s->parsers[s->parsers_num-1]; - *st = s->states[s->parsers_num-1]; -} - -static int mpc_stack_empty(mpc_stack_t *s) { - return s->parsers_num == 0; -} - -/* Stack Result Stuff */ - -static mpc_result_t mpc_result_err(mpc_err_t *e) { - mpc_result_t r; - r.error = e; - return r; -} - -static mpc_result_t mpc_result_out(mpc_val_t *x) { - mpc_result_t r; - r.output = x; - return r; -} - -static void mpc_stack_results_reserve_more(mpc_stack_t *s) { - if (s->results_num > s->results_slots) { - s->results_slots = s->results_num + s->results_num / 2; - s->results = realloc(s->results, sizeof(mpc_result_t) * s->results_slots); - s->returns = realloc(s->returns, sizeof(int) * s->results_slots); - } -} - -static void mpc_stack_results_reserve_less(mpc_stack_t *s) { - if (s->results_slots > s->results_num + s->results_num / 2 - && s->results_slots > MPC_STACK_MIN) { - s->results_slots = - s->results_num > MPC_STACK_MIN ? - s->results_num : MPC_STACK_MIN; - s->results = realloc(s->results, sizeof(mpc_result_t) * s->results_slots); - s->returns = realloc(s->returns, sizeof(int) * s->results_slots); - } -} - -static void mpc_stack_pushr(mpc_stack_t *s, mpc_result_t x, int r) { - s->results_num++; - mpc_stack_results_reserve_more(s); - s->results[s->results_num-1] = x; - s->returns[s->results_num-1] = r; -} - -static int mpc_stack_popr(mpc_stack_t *s, mpc_result_t *x) { - int r; - *x = s->results[s->results_num-1]; - r = s->returns[s->results_num-1]; - s->results_num--; - mpc_stack_results_reserve_less(s); - return r; -} - -static int mpc_stack_peekr(mpc_stack_t *s, mpc_result_t *x) { - *x = s->results[s->results_num-1]; - return s->returns[s->results_num-1]; -} - -static void mpc_stack_popr_err(mpc_stack_t *s, int n) { - mpc_result_t x; - while (n) { - mpc_stack_popr(s, &x); - mpc_stack_err(s, x.error); - n--; - } -} - -static void mpc_stack_popr_out(mpc_stack_t *s, int n, mpc_dtor_t *ds) { - mpc_result_t x; - while (n) { - mpc_stack_popr(s, &x); - ds[n-1](x.output); - n--; - } -} - -static void mpc_stack_popr_out_single(mpc_stack_t *s, int n, mpc_dtor_t dx) { - mpc_result_t x; - while (n) { - mpc_stack_popr(s, &x); - dx(x.output); - n--; - } -} - -static void mpc_stack_popr_n(mpc_stack_t *s, int n) { - mpc_result_t x; - while (n) { - mpc_stack_popr(s, &x); - n--; - } -} - -static mpc_val_t *mpc_stack_merger_out(mpc_stack_t *s, int n, mpc_fold_t f) { - mpc_val_t *x = f(n, (mpc_val_t**)(&s->results[s->results_num-n])); - mpc_stack_popr_n(s, n); - return x; -} - -static mpc_err_t *mpc_stack_merger_err(mpc_stack_t *s, int n) { - mpc_err_t *x = mpc_err_or((mpc_err_t**)(&s->results[s->results_num-n]), n); - mpc_stack_popr_n(s, n); - return x; -} - /* ** This is rather pleasant. The core parsing routine ** is written in about 200 lines of C. @@ -977,233 +758,227 @@ static mpc_err_t *mpc_stack_merger_err(mpc_stack_t *s, int n) { ** Particularly nice are the `or` and `and` ** types which have a broken but mirrored structure ** with return value and error reflected. -** -** When this function was written in recursive form -** it looked pretty nice. But I've since switched -** it around to an awkward while loop. It was an -** unfortunate change for code simplicity but it -** is noble in the name of performance (and -** not smashing the stack). -** -** But it is now a pretty ugly beast... */ -#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_PRIMITIVE(x, f) if (f) { MPC_SUCCESS(x); } else { MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Incorrect Input")); } +#define MPC_SUCCESS(x) r->output = x; return 1 +#define MPC_FAILURE(x) r->error = x; return 0 +#define MPC_PRIMITIVE(x) \ + if (x) { MPC_SUCCESS(r->output); } \ + 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) { - - /* Stack */ - int st = 0; - mpc_parser_t *p = NULL; - mpc_stack_t *stk = mpc_stack_new(i->filename); - - /* Variables */ - char *s; - mpc_result_t r; +enum { + MPC_PARSE_STACK_MIN = 8 +}; - /* Go! */ - mpc_stack_pushp(stk, init); +int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { - while (!mpc_stack_empty(stk)) { + int j = 0, k = 0; + mpc_result_t results_stk[MPC_PARSE_STACK_MIN]; + mpc_result_t *results; + int results_slots = MPC_PARSE_STACK_MIN; + + switch (p->type) { + + /* Basic Parsers */ + + case MPC_TYPE_ANY: MPC_PRIMITIVE(mpc_input_any(i, (char**)&r->output)); + case MPC_TYPE_SINGLE: MPC_PRIMITIVE(mpc_input_char(i, p->data.single.x, (char**)&r->output)); + case MPC_TYPE_RANGE: MPC_PRIMITIVE(mpc_input_range(i, p->data.range.x, p->data.range.y, (char**)&r->output)); + case MPC_TYPE_ONEOF: MPC_PRIMITIVE(mpc_input_oneof(i, p->data.string.x, (char**)&r->output)); + case MPC_TYPE_NONEOF: MPC_PRIMITIVE(mpc_input_noneof(i, p->data.string.x, (char**)&r->output)); + case MPC_TYPE_SATISFY: MPC_PRIMITIVE(mpc_input_satisfy(i, p->data.satisfy.f, (char**)&r->output)); + case MPC_TYPE_STRING: MPC_PRIMITIVE(mpc_input_string(i, p->data.string.x, (char**)&r->output)); + + /* Other parsers */ - mpc_stack_peepp(stk, &p, &st); + case MPC_TYPE_UNDEFINED: MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Parser Undefined!")); + case MPC_TYPE_PASS: MPC_SUCCESS(NULL); + case MPC_TYPE_FAIL: MPC_FAILURE(mpc_err_fail(i->filename, i->state, p->data.fail.m)); + case MPC_TYPE_LIFT: MPC_SUCCESS(p->data.lift.lf()); + case MPC_TYPE_LIFT_VAL: MPC_SUCCESS(p->data.lift.x); + case MPC_TYPE_STATE: MPC_SUCCESS(mpc_state_copy(i->state)); - switch (p->type) { + case MPC_TYPE_ANCHOR: + if (mpc_input_anchor(i, p->data.anchor.f)) { + MPC_SUCCESS(NULL); + } else { + MPC_FAILURE(mpc_err_new(i->filename, i->state, "anchor", mpc_input_peekc(i))); + } + + /* Application Parsers */ + + case MPC_TYPE_EXPECT: + if (mpc_parse_input(i, p->data.expect.x, r)) { + MPC_SUCCESS(r->output); + } else { + mpc_err_delete(r->error); + MPC_FAILURE(mpc_err_new(i->filename, i->state, p->data.expect.m, mpc_input_peekc(i))); + } + + case MPC_TYPE_APPLY: + if (mpc_parse_input(i, p->data.apply.x, r)) { + MPC_SUCCESS(p->data.apply.f(r->output)); + } else { + MPC_FAILURE(r->output); + } + + case MPC_TYPE_APPLY_TO: + if (mpc_parse_input(i, p->data.apply_to.x, r)) { + MPC_SUCCESS(p->data.apply_to.f(r->output, p->data.apply_to.d)); + } else { + MPC_FAILURE(r->error); + } + + case MPC_TYPE_PREDICT: + mpc_input_backtrack_disable(i); + if (mpc_parse_input(i, p->data.predict.x, r)) { + mpc_input_backtrack_enable(i); + MPC_SUCCESS(r->output); + } else { + mpc_input_backtrack_enable(i); + MPC_FAILURE(r->error); + } + + /* Optional Parsers */ + + /* TODO: Update Not Error Message */ + + case MPC_TYPE_NOT: + mpc_input_mark(i); + if (mpc_parse_input(i, p->data.not.x, r)) { + mpc_input_rewind(i); + p->data.not.dx(r->output); + MPC_FAILURE(mpc_err_new(i->filename, i->state, "opposite", mpc_input_peekc(i))); + } else { + mpc_input_unmark(i); + mpc_err_delete(r->error); + MPC_SUCCESS(p->data.not.lf()); + } + + case MPC_TYPE_MAYBE: + if (mpc_parse_input(i, p->data.not.x, r)) { + MPC_SUCCESS(r->output); + } else { + mpc_err_delete(r->error); + MPC_SUCCESS(p->data.not.lf()); + } + + /* Repeat Parsers */ + + case MPC_TYPE_MANY: - /* Basic Parsers */ + results = malloc(sizeof(mpc_result_t) * results_slots); + + while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { + j++; + if (j >= results_slots) { + results_slots = j + j / 2; + results = realloc(results, sizeof(mpc_result_t) * results_slots); + } + } + + mpc_err_delete(results[j].error); + MPC_SUCCESS(p->data.repeat.f(j, (mpc_val_t**)results); free(results)); + + case MPC_TYPE_MANY1: + + results = malloc(sizeof(mpc_result_t) * results_slots); + + while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { + j++; + if (j >= results_slots) { + results_slots = j + j / 2; + results = realloc(results, sizeof(mpc_result_t) * results_slots); + } + } + + if (j == 0) { + MPC_FAILURE(mpc_err_many1(results[0].error); free(results)); + } else { + mpc_err_delete(results[j].error); + MPC_SUCCESS(p->data.repeat.f(j, (mpc_val_t**)results); free(results)); + } + + case MPC_TYPE_COUNT: + + results = p->data.repeat.n > MPC_PARSE_STACK_MIN + ? malloc(sizeof(mpc_result_t) * p->data.repeat.n) + : results_stk; + + while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { + j++; + if (j == p->data.repeat.n) { break; } + } + + if (j == p->data.repeat.n) { + MPC_SUCCESS(p->data.repeat.f(j, (mpc_val_t**)results); + if (p->data.repeat.n > MPC_PARSE_STACK_MIN) { free(results); }); + } else { + for (k = 0; k < j; k++) { + p->data.repeat.dx(results[k].output); + } + MPC_FAILURE(mpc_err_count(results[j].error, p->data.repeat.n); + if (p->data.repeat.n > MPC_PARSE_STACK_MIN) { free(results); }); + } + + /* Combinatory Parsers */ + + case MPC_TYPE_OR: + + if (p->data.or.n == 0) { MPC_SUCCESS(NULL); } + + results = p->data.or.n > MPC_PARSE_STACK_MIN + ? malloc(sizeof(mpc_result_t) * p->data.or.n) + : results_stk; + + for (j = 0; j < p->data.or.n; j++) { + if (mpc_parse_input(i, p->data.or.xs[j], &results[j])) { + for (k = 0; k < j; k++) { + mpc_err_delete(results[k].error); + } + MPC_SUCCESS(results[j].output; + if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); + } + } - 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)); + MPC_FAILURE(mpc_err_or((mpc_err_t**)results, j); + if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); + + case MPC_TYPE_AND: - /* Other parsers */ + if (p->data.and.n == 0) { MPC_SUCCESS(NULL); } - case MPC_TYPE_UNDEFINED: MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Parser Undefined!")); - case MPC_TYPE_PASS: MPC_SUCCESS(NULL); - case MPC_TYPE_FAIL: MPC_FAILURE(mpc_err_fail(i->filename, i->state, p->data.fail.m)); - case MPC_TYPE_LIFT: MPC_SUCCESS(p->data.lift.lf()); - case MPC_TYPE_LIFT_VAL: MPC_SUCCESS(p->data.lift.x); - case MPC_TYPE_STATE: MPC_SUCCESS(mpc_state_copy(i->state)); + results = p->data.or.n > MPC_PARSE_STACK_MIN + ? malloc(sizeof(mpc_result_t) * p->data.or.n) + : results_stk; - case MPC_TYPE_ANCHOR: - if (mpc_input_anchor(i, p->data.anchor.f)) { - MPC_SUCCESS(NULL); - } else { - MPC_FAILURE(mpc_err_new(i->filename, i->state, "anchor", mpc_input_peekc(i))); - } - - /* Application Parsers */ - - case MPC_TYPE_EXPECT: - if (st == 0) { MPC_CONTINUE(1, p->data.expect.x); } - if (st == 1) { - if (mpc_stack_popr(stk, &r)) { - MPC_SUCCESS(r.output); - } else { - mpc_err_delete(r.error); - MPC_FAILURE(mpc_err_new(i->filename, i->state, p->data.expect.m, mpc_input_peekc(i))); + mpc_input_mark(i); + for (j = 0; j < p->data.and.n; j++) { + if (!mpc_parse_input(i, p->data.and.xs[j], &results[j])) { + mpc_input_rewind(i); + for (k = 0; k < j; k++) { + p->data.and.dxs[k](results[k].output); } + MPC_FAILURE(results[j].error; + if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); } + } + mpc_input_unmark(i); - case MPC_TYPE_APPLY: - if (st == 0) { MPC_CONTINUE(1, p->data.apply.x); } - if (st == 1) { - if (mpc_stack_popr(stk, &r)) { - MPC_SUCCESS(p->data.apply.f(r.output)); - } else { - MPC_FAILURE(r.error); - } - } + MPC_SUCCESS(p->data.and.f(j, (mpc_val_t**)results); + if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); + + /* End */ + + default: - case MPC_TYPE_APPLY_TO: - if (st == 0) { MPC_CONTINUE(1, p->data.apply_to.x); } - if (st == 1) { - if (mpc_stack_popr(stk, &r)) { - MPC_SUCCESS(p->data.apply_to.f(r.output, p->data.apply_to.d)); - } else { - MPC_FAILURE(r.error); - } - } - - case MPC_TYPE_PREDICT: - if (st == 0) { mpc_input_backtrack_disable(i); MPC_CONTINUE(1, p->data.predict.x); } - if (st == 1) { - mpc_input_backtrack_enable(i); - mpc_stack_popp(stk, &p, &st); - continue; - } - - /* Optional Parsers */ - - /* TODO: Update Not Error Message */ - - case MPC_TYPE_NOT: - if (st == 0) { mpc_input_mark(i); MPC_CONTINUE(1, p->data.not.x); } - if (st == 1) { - if (mpc_stack_popr(stk, &r)) { - mpc_input_rewind(i); - p->data.not.dx(r.output); - MPC_FAILURE(mpc_err_new(i->filename, i->state, "opposite", mpc_input_peekc(i))); - } else { - mpc_input_unmark(i); - mpc_stack_err(stk, r.error); - MPC_SUCCESS(p->data.not.lf()); - } - } - - case MPC_TYPE_MAYBE: - if (st == 0) { MPC_CONTINUE(1, p->data.not.x); } - if (st == 1) { - if (mpc_stack_popr(stk, &r)) { - MPC_SUCCESS(r.output); - } else { - mpc_stack_err(stk, r.error); - MPC_SUCCESS(p->data.not.lf()); - } - } - - /* Repeat Parsers */ - - case MPC_TYPE_MANY: - if (st == 0) { MPC_CONTINUE(st+1, p->data.repeat.x); } - if (st > 0) { - if (mpc_stack_peekr(stk, &r)) { - MPC_CONTINUE(st+1, p->data.repeat.x); - } else { - mpc_stack_popr(stk, &r); - mpc_stack_err(stk, r.error); - MPC_SUCCESS(mpc_stack_merger_out(stk, st-1, p->data.repeat.f)); - } - } - - case MPC_TYPE_MANY1: - if (st == 0) { MPC_CONTINUE(st+1, p->data.repeat.x); } - if (st > 0) { - if (mpc_stack_peekr(stk, &r)) { - MPC_CONTINUE(st+1, p->data.repeat.x); - } else { - if (st == 1) { - mpc_stack_popr(stk, &r); - MPC_FAILURE(mpc_err_many1(r.error)); - } else { - mpc_stack_popr(stk, &r); - mpc_stack_err(stk, r.error); - MPC_SUCCESS(mpc_stack_merger_out(stk, st-1, p->data.repeat.f)); - } - } - } - - case MPC_TYPE_COUNT: - if (st == 0) { mpc_input_mark(i); MPC_CONTINUE(st+1, p->data.repeat.x); } - if (st > 0) { - if (!mpc_stack_peekr(stk, &r)) { - mpc_stack_popr(stk, &r); - mpc_stack_popr_out_single(stk, st-1, p->data.repeat.dx); - mpc_input_rewind(i); - MPC_FAILURE(mpc_err_count(r.error, p->data.repeat.n)); - } else { - if (st < p->data.repeat.n) { - MPC_CONTINUE(st+1, p->data.repeat.x); - } else { - mpc_input_unmark(i); - MPC_SUCCESS(mpc_stack_merger_out(stk, st, p->data.repeat.f)); - } - } - } - - /* Combinatory Parsers */ - - case MPC_TYPE_OR: - - if (p->data.or.n == 0) { MPC_SUCCESS(NULL); } - - if (st == 0) { MPC_CONTINUE(st+1, p->data.or.xs[st]); } - if (st <= p->data.or.n) { - if (mpc_stack_peekr(stk, &r)) { - mpc_stack_popr(stk, &r); - mpc_stack_popr_err(stk, st-1); - MPC_SUCCESS(r.output); - } - if (st < p->data.or.n) { MPC_CONTINUE(st+1, p->data.or.xs[st]); } - if (st == p->data.or.n) { MPC_FAILURE(mpc_stack_merger_err(stk, p->data.or.n)); } - } - - case MPC_TYPE_AND: - - 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) { - if (!mpc_stack_peekr(stk, &r)) { - mpc_input_rewind(i); - mpc_stack_popr(stk, &r); - mpc_stack_popr_out(stk, st-1, p->data.and.dxs); - MPC_FAILURE(r.error); - } - if (st < p->data.and.n) { MPC_CONTINUE(st+1, p->data.and.xs[st]); } - if (st == p->data.and.n) { mpc_input_unmark(i); MPC_SUCCESS(mpc_stack_merger_out(stk, p->data.and.n, p->data.and.f)); } - } - - /* End */ - - default: - - MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Unknown Parser Type Id!")); - } + MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Unknown Parser Type Id!")); } - return mpc_stack_terminate(stk, final); + return 0; } -#undef MPC_CONTINUE #undef MPC_SUCCESS #undef MPC_FAILURE #undef MPC_PRIMITIVE @@ -2011,7 +1786,7 @@ static mpc_val_t *mpcf_re_range(mpc_val_t *x) { start = s[i-1]+1; end = s[i+1]-1; for (j = start; j <= end; j++) { - range = realloc(range, strlen(range) + 1 + 1); + range = realloc(range, strlen(range) + 1 + 1 + 1); range[strlen(range) + 1] = '\0'; range[strlen(range) + 0] = j; } @@ -2230,7 +2005,7 @@ static mpc_val_t *mpcf_unescape_new(mpc_val_t *x, const char *input, const char while (output[i]) { if ((*(s+0)) == output[i][0] && (*(s+1)) == output[i][1]) { - y = realloc(y, strlen(y) + 2); + y = realloc(y, strlen(y) + 1 + 1); buff[0] = input[i]; buff[1] = '\0'; strcat(y, buff); found = 1; @@ -2241,7 +2016,7 @@ static mpc_val_t *mpcf_unescape_new(mpc_val_t *x, const char *input, const char } if (!found) { - y = realloc(y, strlen(y) + 2); + y = realloc(y, strlen(y) + 1 + 1); buff[0] = *s; buff[1] = '\0'; strcat(y, buff); } @@ -3363,7 +3138,6 @@ static void mpc_optimise_unretained(mpc_parser_t *p, int force) { int i, n, m; mpc_parser_t *t; - mpc_parser_t swp; if (p->retained && !force) { return; } @@ -3428,10 +3202,11 @@ static void mpc_optimise_unretained(mpc_parser_t *p, int force) { && p->data.and.xs[0]->type == MPC_TYPE_PASS && !p->data.and.xs[0]->retained && p->data.and.f == mpcf_fold_ast) { - memcpy(&swp, p->data.and.xs[1], sizeof(mpc_parser_t)); + t = p->data.and.xs[1]; mpc_delete(p->data.and.xs[0]); - free(p->data.and.xs); free(p->data.and.dxs); - memcpy(p, &swp, sizeof(mpc_parser_t)); + free(p->data.and.xs); free(p->data.and.dxs); free(p->name); + memcpy(p, t, sizeof(mpc_parser_t)); + free(t); continue; } @@ -3477,10 +3252,11 @@ static void mpc_optimise_unretained(mpc_parser_t *p, int force) { && p->data.and.xs[0]->data.lift.lf == mpcf_ctor_str && !p->data.and.xs[0]->retained && p->data.and.f == mpcf_strfold) { - memcpy(&swp, p->data.and.xs[1], sizeof(mpc_parser_t)); + t = p->data.and.xs[1]; mpc_delete(p->data.and.xs[0]); - free(p->data.and.xs); free(p->data.and.dxs); - memcpy(p, &swp, sizeof(mpc_parser_t)); + free(p->data.and.xs); free(p->data.and.dxs); free(p->name); + memcpy(p, t, sizeof(mpc_parser_t)); + free(t); continue; } From 99732cee3003bc289fcec7ed61629d273e0f9fcf Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Thu, 12 Nov 2015 15:58:05 +0000 Subject: [PATCH 28/49] More optimisations including a pool memory allocator and suppression of error generation when not required. --- mpc.c | 918 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 577 insertions(+), 341 deletions(-) diff --git a/mpc.c b/mpc.c index 2ed905b..18e196d 100644 --- a/mpc.c +++ b/mpc.c @@ -20,258 +20,6 @@ static mpc_state_t mpc_state_new(void) { return s; } -static mpc_state_t *mpc_state_copy(mpc_state_t s) { - mpc_state_t *r = malloc(sizeof(mpc_state_t)); - memcpy(r, &s, sizeof(mpc_state_t)); - return r; -} - -/* -** Error Type -*/ - -static mpc_err_t *mpc_err_new(const char *filename, mpc_state_t s, const char *expected, char recieved) { - mpc_err_t *x = malloc(sizeof(mpc_err_t)); - x->filename = malloc(strlen(filename) + 1); - strcpy(x->filename, filename); - x->state = s; - x->expected_num = 1; - x->expected = malloc(sizeof(char*)); - x->expected[0] = malloc(strlen(expected) + 1); - strcpy(x->expected[0], expected); - x->failure = NULL; - x->recieved = recieved; - return x; -} - -static mpc_err_t *mpc_err_fail(const char *filename, mpc_state_t s, const char *failure) { - mpc_err_t *x = malloc(sizeof(mpc_err_t)); - x->filename = malloc(strlen(filename) + 1); - strcpy(x->filename, filename); - x->state = s; - x->expected_num = 0; - x->expected = NULL; - x->failure = malloc(strlen(failure) + 1); - strcpy(x->failure, failure); - x->recieved = ' '; - return x; -} - -void mpc_err_delete(mpc_err_t *x) { - - int i; - for (i = 0; i < x->expected_num; i++) { - free(x->expected[i]); - } - - free(x->expected); - free(x->filename); - free(x->failure); - free(x); -} - -static int mpc_err_contains_expected(mpc_err_t *x, char *expected) { - - int i; - for (i = 0; i < x->expected_num; i++) { - if (strcmp(x->expected[i], expected) == 0) { return 1; } - } - - return 0; -} - -static void mpc_err_add_expected(mpc_err_t *x, char *expected) { - - x->expected_num++; - x->expected = realloc(x->expected, sizeof(char*) * x->expected_num); - x->expected[x->expected_num-1] = malloc(strlen(expected) + 1); - strcpy(x->expected[x->expected_num-1], expected); - -} - -static void mpc_err_clear_expected(mpc_err_t *x, char *expected) { - - int i; - for (i = 0; i < x->expected_num; i++) { - free(x->expected[i]); - } - x->expected_num = 1; - x->expected = realloc(x->expected, sizeof(char*) * x->expected_num); - x->expected[0] = malloc(strlen(expected) + 1); - strcpy(x->expected[0], expected); - -} - -void mpc_err_print(mpc_err_t *x) { - mpc_err_print_to(x, stdout); -} - -void mpc_err_print_to(mpc_err_t *x, FILE *f) { - char *str = mpc_err_string(x); - fprintf(f, "%s", str); - free(str); -} - -void mpc_err_string_cat(char *buffer, int *pos, int *max, char const *fmt, ...) { - /* TODO: Error Checking on Length */ - int left = ((*max) - (*pos)); - va_list va; - va_start(va, fmt); - if (left < 0) { left = 0;} - (*pos) += vsprintf(buffer + (*pos), fmt, va); - va_end(va); -} - -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) { - - case '\a': return "bell"; - case '\b': return "backspace"; - case '\f': return "formfeed"; - case '\r': return "carriage return"; - case '\v': return "vertical tab"; - case '\0': return "end of input"; - case '\n': return "newline"; - case '\t': return "tab"; - case ' ' : return "space"; - default: - char_unescape_buffer[1] = c; - return char_unescape_buffer; - } - -} - -char *mpc_err_string(mpc_err_t *x) { - - int i; - int pos = 0; - int max = 1023; - char *buffer = calloc(1, 1024); - - if (x->failure) { - mpc_err_string_cat(buffer, &pos, &max, - "%s: error: %s\n", x->filename, x->failure); - return buffer; - } - - mpc_err_string_cat(buffer, &pos, &max, - "%s:%i:%i: error: expected ", x->filename, x->state.row+1, x->state.col+1); - - if (x->expected_num == 0) { mpc_err_string_cat(buffer, &pos, &max, "ERROR: NOTHING EXPECTED"); } - if (x->expected_num == 1) { mpc_err_string_cat(buffer, &pos, &max, "%s", x->expected[0]); } - if (x->expected_num >= 2) { - - for (i = 0; i < x->expected_num-2; i++) { - mpc_err_string_cat(buffer, &pos, &max, "%s, ", x->expected[i]); - } - - mpc_err_string_cat(buffer, &pos, &max, "%s or %s", - x->expected[x->expected_num-2], - x->expected[x->expected_num-1]); - } - - mpc_err_string_cat(buffer, &pos, &max, " at "); - mpc_err_string_cat(buffer, &pos, &max, mpc_err_char_unescape(x->recieved)); - mpc_err_string_cat(buffer, &pos, &max, "\n"); - - return realloc(buffer, strlen(buffer) + 1); -} - -static mpc_err_t *mpc_err_or(mpc_err_t** x, int n) { - - int i, j; - mpc_err_t *e = malloc(sizeof(mpc_err_t)); - e->state = mpc_state_invalid(); - e->expected_num = 0; - e->expected = NULL; - e->failure = NULL; - e->filename = malloc(strlen(x[0]->filename)+1); - strcpy(e->filename, x[0]->filename); - - for (i = 0; i < n; i++) { - if (x[i]->state.pos > e->state.pos) { e->state = x[i]->state; } - } - - for (i = 0; i < n; i++) { - - if (x[i]->state.pos < e->state.pos) { continue; } - - if (x[i]->failure) { - e->failure = malloc(strlen(x[i]->failure)+1); - strcpy(e->failure, x[i]->failure); - break; - } - - e->recieved = x[i]->recieved; - - for (j = 0; j < x[i]->expected_num; j++) { - if (!mpc_err_contains_expected(e, x[i]->expected[j])) { mpc_err_add_expected(e, x[i]->expected[j]); } - } - } - - for (i = 0; i < n; i++) { - mpc_err_delete(x[i]); - } - - return e; -} - -static mpc_err_t *mpc_err_repeat(mpc_err_t *x, const char *prefix) { - - int i; - char *expect = malloc(strlen(prefix) + 1); - strcpy(expect, prefix); - - if (x->expected_num == 1) { - expect = realloc(expect, strlen(expect) + strlen(x->expected[0]) + 1); - strcat(expect, x->expected[0]); - } - - if (x->expected_num > 1) { - - for (i = 0; i < x->expected_num-2; i++) { - expect = realloc(expect, strlen(expect) + strlen(x->expected[i]) + strlen(", ") + 1); - strcat(expect, x->expected[i]); - strcat(expect, ", "); - } - - expect = realloc(expect, strlen(expect) + strlen(x->expected[x->expected_num-2]) + strlen(" or ") + 1); - strcat(expect, x->expected[x->expected_num-2]); - strcat(expect, " or "); - expect = realloc(expect, strlen(expect) + strlen(x->expected[x->expected_num-1]) + 1); - strcat(expect, x->expected[x->expected_num-1]); - - } - - mpc_err_clear_expected(x, expect); - free(expect); - - return x; - -} - -static mpc_err_t *mpc_err_many1(mpc_err_t *x) { - return mpc_err_repeat(x, "one or more of "); -} - -static mpc_err_t *mpc_err_count(mpc_err_t *x, int n) { - mpc_err_t *y; - int digits = n/10 + 1; - char *prefix = malloc(digits + strlen(" of ") + 1); - sprintf(prefix, "%i of ", n); - y = mpc_err_repeat(x, prefix); - free(prefix); - return y; -} - /* ** Input Type */ @@ -313,6 +61,18 @@ enum { MPC_INPUT_PIPE = 2 }; +enum { + MPC_INPUT_MARKS_MIN = 32 +}; + +enum { + MPC_INPUT_MEM_NUM = 512 +}; + +typedef struct { + char mem[64]; +} mpc_mem_t; + typedef struct { int type; @@ -323,20 +83,21 @@ typedef struct { char *buffer; FILE *file; + int suppress; int backtrack; int marks_slots; int marks_num; - mpc_state_t* marks; - char* lasts; + mpc_state_t *marks; + char *lasts; char last; + size_t mem_index; + char mem_full[MPC_INPUT_MEM_NUM]; + mpc_mem_t mem[MPC_INPUT_MEM_NUM]; + } mpc_input_t; -enum { - MPC_INPUT_MARKS_MIN = 32 -}; - static mpc_input_t *mpc_input_new_string(const char *filename, const char *string) { mpc_input_t *i = malloc(sizeof(mpc_input_t)); @@ -352,14 +113,17 @@ static mpc_input_t *mpc_input_new_string(const char *filename, const char *strin i->buffer = NULL; i->file = NULL; + i->suppress = 0; i->backtrack = 1; i->marks_num = 0; i->marks_slots = MPC_INPUT_MARKS_MIN; i->marks = malloc(sizeof(mpc_state_t) * i->marks_slots); i->lasts = malloc(sizeof(char) * i->marks_slots); - i->last = '\0'; + i->mem_index = 0; + memset(i->mem_full, 0, sizeof(mpc_mem_t) * MPC_INPUT_MEM_NUM); + return i; } @@ -377,14 +141,17 @@ static mpc_input_t *mpc_input_new_pipe(const char *filename, FILE *pipe) { i->buffer = NULL; i->file = pipe; + i->suppress = 0; i->backtrack = 1; i->marks_num = 0; i->marks_slots = MPC_INPUT_MARKS_MIN; i->marks = malloc(sizeof(mpc_state_t) * i->marks_slots); i->lasts = malloc(sizeof(char) * i->marks_slots); - i->last = '\0'; + i->mem_index = 0; + memset(i->mem_full, 0, sizeof(mpc_mem_t) * MPC_INPUT_MEM_NUM); + return i; } @@ -402,14 +169,17 @@ static mpc_input_t *mpc_input_new_file(const char *filename, FILE *file) { i->buffer = NULL; i->file = file; + i->suppress = 0; i->backtrack = 1; i->marks_num = 0; i->marks_slots = MPC_INPUT_MARKS_MIN; i->marks = malloc(sizeof(mpc_state_t) * i->marks_slots); i->lasts = malloc(sizeof(char) * i->marks_slots); - i->last = '\0'; + i->mem_index = 0; + memset(i->mem_full, 0, sizeof(mpc_mem_t) * MPC_INPUT_MEM_NUM); + return i; } @@ -425,9 +195,76 @@ static void mpc_input_delete(mpc_input_t *i) { free(i); } +static int mpc_mem_ptr(mpc_input_t *i, void *p) { + return + (char*)p >= (char*)(i->mem) && + (char*)p < (char*)(i->mem) + (MPC_INPUT_MEM_NUM * sizeof(mpc_mem_t)); +} + +static void *mpc_malloc(mpc_input_t *i, size_t n) { + size_t j; + char *p; + + if (n > sizeof(mpc_mem_t)) { return malloc(n); } + + j = i->mem_index; + do { + if (!i->mem_full[i->mem_index]) { + p = (void*)(i->mem + i->mem_index); + i->mem_full[i->mem_index] = 1; + i->mem_index = (i->mem_index+1) % MPC_INPUT_MEM_NUM; + return p; + } + i->mem_index = (i->mem_index+1) % MPC_INPUT_MEM_NUM; + } while (j != i->mem_index); + + return malloc(n); +} + +static void *mpc_calloc(mpc_input_t *i, size_t n, size_t m) { + char *x = mpc_malloc(i, n * m); + memset(x, 0, n * m); + return x; +} + +static void mpc_free(mpc_input_t *i, void *p) { + size_t j; + if (!mpc_mem_ptr(i, p)) { free(p); return; } + j = ((size_t)(((char*)p) - ((char*)i->mem))) / sizeof(mpc_mem_t); + i->mem_full[j] = 0; +} + +static void *mpc_realloc(mpc_input_t *i, void *p, size_t n) { + + char *q = NULL; + + if (!mpc_mem_ptr(i, p)) { return realloc(p, n); } + + if (n > sizeof(mpc_mem_t)) { + q = malloc(n); + memcpy(q, p, sizeof(mpc_mem_t)); + mpc_free(i, p); + return q; + } + + return p; +} + +static void *mpc_export(mpc_input_t *i, void *p) { + char *q = NULL; + if (!mpc_mem_ptr(i, p)) { return p; } + q = malloc(sizeof(mpc_mem_t)); + memcpy(q, p, sizeof(mpc_mem_t)); + mpc_free(i, p); + return q; +} + static void mpc_input_backtrack_disable(mpc_input_t *i) { i->backtrack--; } static void mpc_input_backtrack_enable(mpc_input_t *i) { i->backtrack++; } +static void mpc_input_suppress_disable(mpc_input_t *i) { i->suppress--; } +static void mpc_input_suppress_enable(mpc_input_t *i) { i->suppress++; } + static void mpc_input_mark(mpc_input_t *i) { if (i->backtrack < 1) { return; } @@ -583,10 +420,8 @@ static int mpc_input_failure(mpc_input_t *i, char c) { static int mpc_input_success(mpc_input_t *i, char c, char **o) { - if (i->type == MPC_INPUT_PIPE && - i->buffer && - !mpc_input_buffer_in_range(i)) { - + if (i->type == MPC_INPUT_PIPE + && i->buffer && !mpc_input_buffer_in_range(i)) { i->buffer = realloc(i->buffer, strlen(i->buffer) + 2); i->buffer[strlen(i->buffer) + 1] = '\0'; i->buffer[strlen(i->buffer) + 0] = c; @@ -602,7 +437,7 @@ static int mpc_input_success(mpc_input_t *i, char c, char **o) { } if (o) { - (*o) = malloc(2); + (*o) = mpc_malloc(i, 2); (*o)[0] = c; (*o)[1] = '\0'; } @@ -648,14 +483,11 @@ static int mpc_input_satisfy(mpc_input_t *i, int(*cond)(char), char **o) { static int mpc_input_string(mpc_input_t *i, const char *c, char **o) { - char *co = NULL; const char *x = c; mpc_input_mark(i); while (*x) { - if (mpc_input_char(i, *x, &co)) { - free(co); - } else { + if (!mpc_input_char(i, *x, NULL)) { mpc_input_rewind(i); return 0; } @@ -663,7 +495,7 @@ static int mpc_input_string(mpc_input_t *i, const char *c, char **o) { } mpc_input_unmark(i); - *o = malloc(strlen(c) + 1); + *o = mpc_malloc(i, strlen(c) + 1); strcpy(*o, c); return 1; } @@ -672,6 +504,308 @@ static int mpc_input_anchor(mpc_input_t* i, int(*f)(char,char)) { return f(i->last, mpc_input_peekc(i)); } +static mpc_state_t *mpc_input_state_copy(mpc_input_t *i) { + mpc_state_t *r = mpc_malloc(i, sizeof(mpc_state_t)); + memcpy(r, &i->state, sizeof(mpc_state_t)); + return r; +} + +/* +** Error Type +*/ + +void mpc_err_delete(mpc_err_t *x) { + int i; + for (i = 0; i < x->expected_num; i++) { free(x->expected[i]); } + free(x->expected); + free(x->filename); + free(x->failure); + free(x); +} + +void mpc_err_print(mpc_err_t *x) { + mpc_err_print_to(x, stdout); +} + +void mpc_err_print_to(mpc_err_t *x, FILE *f) { + char *str = mpc_err_string(x); + fprintf(f, "%s", str); + free(str); +} + +static void mpc_err_string_cat(char *buffer, int *pos, int *max, char const *fmt, ...) { + /* TODO: Error Checking on Length */ + int left = ((*max) - (*pos)); + va_list va; + va_start(va, fmt); + if (left < 0) { left = 0;} + (*pos) += vsprintf(buffer + (*pos), fmt, va); + va_end(va); +} + +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) { + case '\a': return "bell"; + case '\b': return "backspace"; + case '\f': return "formfeed"; + case '\r': return "carriage return"; + case '\v': return "vertical tab"; + case '\0': return "end of input"; + case '\n': return "newline"; + case '\t': return "tab"; + case ' ' : return "space"; + default: + char_unescape_buffer[1] = c; + return char_unescape_buffer; + } + +} + +char *mpc_err_string(mpc_err_t *x) { + + int i; + int pos = 0; + int max = 1023; + char *buffer = calloc(1, 1024); + + if (x->failure) { + mpc_err_string_cat(buffer, &pos, &max, + "%s: error: %s\n", x->filename, x->failure); + return buffer; + } + + mpc_err_string_cat(buffer, &pos, &max, + "%s:%i:%i: error: expected ", x->filename, x->state.row+1, x->state.col+1); + + if (x->expected_num == 0) { mpc_err_string_cat(buffer, &pos, &max, "ERROR: NOTHING EXPECTED"); } + if (x->expected_num == 1) { mpc_err_string_cat(buffer, &pos, &max, "%s", x->expected[0]); } + if (x->expected_num >= 2) { + + for (i = 0; i < x->expected_num-2; i++) { + mpc_err_string_cat(buffer, &pos, &max, "%s, ", x->expected[i]); + } + + mpc_err_string_cat(buffer, &pos, &max, "%s or %s", + x->expected[x->expected_num-2], + x->expected[x->expected_num-1]); + } + + mpc_err_string_cat(buffer, &pos, &max, " at "); + mpc_err_string_cat(buffer, &pos, &max, mpc_err_char_unescape(x->recieved)); + mpc_err_string_cat(buffer, &pos, &max, "\n"); + + return realloc(buffer, strlen(buffer) + 1); +} + +static mpc_err_t *mpc_err_new(mpc_input_t *i, const char *expected) { + mpc_err_t *x; + if (i->suppress) { return NULL; } + x = mpc_malloc(i, sizeof(mpc_err_t)); + x->filename = mpc_malloc(i, strlen(i->filename) + 1); + strcpy(x->filename, i->filename); + x->state = i->state; + x->expected_num = 1; + x->expected = mpc_malloc(i, sizeof(char*)); + x->expected[0] = mpc_malloc(i, strlen(expected) + 1); + strcpy(x->expected[0], expected); + x->failure = NULL; + x->recieved = mpc_input_peekc(i); + return x; +} + +static mpc_err_t *mpc_err_fail(mpc_input_t *i, const char *failure) { + mpc_err_t *x; + if (i->suppress) { return NULL; } + x = mpc_malloc(i, sizeof(mpc_err_t)); + x->filename = mpc_malloc(i, strlen(i->filename) + 1); + strcpy(x->filename, i->filename); + x->state = i->state; + x->expected_num = 0; + x->expected = NULL; + x->failure = mpc_malloc(i, strlen(failure) + 1); + strcpy(x->failure, failure); + x->recieved = ' '; + return x; +} + +static mpc_err_t *mpc_err_file(const char *filename, const char *failure) { + mpc_err_t *x; + x = malloc(sizeof(mpc_err_t)); + x->filename = malloc(strlen(filename) + 1); + strcpy(x->filename, filename); + x->state = mpc_state_new(); + x->expected_num = 0; + x->expected = NULL; + x->failure = malloc(strlen(failure) + 1); + strcpy(x->failure, failure); + x->recieved = ' '; + return x; +} + +static void mpc_err_delete_internal(mpc_input_t *i, mpc_err_t *x) { + int j; + if (i->suppress) { return; } + for (j = 0; j < x->expected_num; j++) { mpc_free(i, x->expected[j]); } + mpc_free(i, x->expected); + mpc_free(i, x->filename); + mpc_free(i, x->failure); + mpc_free(i, x); +} + +static mpc_err_t *mpc_err_export(mpc_input_t *i, mpc_err_t *x) { + int j; + if (i->suppress) { return NULL; } + for (j = 0; j < x->expected_num; j++) { + x->expected[j] = mpc_export(i, x->expected[j]); + } + x->expected = mpc_export(i, x->expected); + x->filename = mpc_export(i, x->filename); + x->failure = mpc_export(i, x->failure); + return mpc_export(i, x); +} + +static int mpc_err_contains_expected(mpc_input_t *i, mpc_err_t *x, char *expected) { + int j; + (void)i; + for (j = 0; j < x->expected_num; j++) { + if (strcmp(x->expected[j], expected) == 0) { return 1; } + } + return 0; +} + +static void mpc_err_add_expected(mpc_input_t *i, mpc_err_t *x, char *expected) { + (void)i; + x->expected_num++; + x->expected = mpc_realloc(i, x->expected, sizeof(char*) * x->expected_num); + x->expected[x->expected_num-1] = mpc_malloc(i, strlen(expected) + 1); + strcpy(x->expected[x->expected_num-1], expected); +} + +static mpc_err_t *mpc_err_or(mpc_input_t *i, mpc_err_t** x, int n) { + + int j, k; + mpc_err_t *e; + + if (i->suppress) { return NULL; } + + e = mpc_malloc(i, sizeof(mpc_err_t)); + e->state = mpc_state_invalid(); + e->expected_num = 0; + e->expected = NULL; + e->failure = NULL; + e->filename = mpc_malloc(i, strlen(x[0]->filename)+1); + strcpy(e->filename, x[0]->filename); + + for (j = 0; j < n; j++) { + if (x[j]->state.pos > e->state.pos) { e->state = x[j]->state; } + } + + for (j = 0; j < n; j++) { + + if (x[j]->state.pos < e->state.pos) { continue; } + + if (x[j]->failure) { + e->failure = mpc_malloc(i, strlen(x[j]->failure)+1); + strcpy(e->failure, x[j]->failure); + break; + } + + e->recieved = x[j]->recieved; + + for (k = 0; k < x[j]->expected_num; k++) { + if (!mpc_err_contains_expected(i, e, x[j]->expected[k])) { + mpc_err_add_expected(i, e, x[j]->expected[k]); + } + } + } + + for (j = 0; j < n; j++) { + mpc_err_delete_internal(i, x[j]); + } + + return e; +} + +static mpc_err_t *mpc_err_repeat(mpc_input_t *i, mpc_err_t *x, const char *prefix) { + + int j = 0; + size_t l = 0; + char *expect = NULL; + + if (i->suppress) { return NULL; } + + if (x->expected_num == 0) { + expect = mpc_calloc(i, 1, 1); + x->expected_num = 1; + x->expected = mpc_realloc(i, x->expected, sizeof(char*) * x->expected_num); + x->expected[0] = expect; + return x; + } + + else if (x->expected_num == 1) { + expect = mpc_malloc(i, strlen(prefix) + strlen(x->expected[0]) + 1); + strcpy(expect, prefix); + strcat(expect, x->expected[0]); + mpc_free(i, x->expected[0]); + x->expected[0] = expect; + return x; + } + + else if (x->expected_num > 1) { + + l += strlen(prefix); + for (j = 0; j < x->expected_num-2; j++) { + l += strlen(x->expected[j]) + strlen(", "); + } + l += strlen(x->expected[x->expected_num-2]); + l += strlen(" or "); + l += strlen(x->expected[x->expected_num-1]); + + expect = mpc_malloc(i, l + 1); + + strcpy(expect, prefix); + for (j = 0; j < x->expected_num-2; j++) { + strcat(expect, x->expected[j]); strcat(expect, ", "); + } + strcat(expect, x->expected[x->expected_num-2]); + strcat(expect, " or "); + strcat(expect, x->expected[x->expected_num-1]); + + for (j = 0; j < x->expected_num; j++) { mpc_free(i, x->expected[j]); } + + x->expected_num = 1; + x->expected = mpc_realloc(i, x->expected, sizeof(char*) * x->expected_num); + x->expected[0] = expect; + return x; + } + + return NULL; +} + +static mpc_err_t *mpc_err_many1(mpc_input_t *i, mpc_err_t *x) { + return mpc_err_repeat(i, x, "one or more of "); +} + +static mpc_err_t *mpc_err_count(mpc_input_t *i, mpc_err_t *x, int n) { + mpc_err_t *y; + int digits = n/10 + 1; + char *prefix; + if (i->suppress) { return NULL; } + prefix = mpc_malloc(i, digits + strlen(" of ") + 1); + sprintf(prefix, "%i of ", n); + y = mpc_err_repeat(i, x, prefix); + mpc_free(i, prefix); + return y; +} + /* ** Parser Type */ @@ -748,27 +882,85 @@ struct mpc_parser_t { mpc_pdata_t data; }; -/* -** This is rather pleasant. The core parsing routine -** is written in about 200 lines of C. -** -** I also love the way in which each parsing type -** concisely matches some construct or pattern. -** -** Particularly nice are the `or` and `and` -** types which have a broken but mirrored structure -** with return value and error reflected. -*/ +static mpc_val_t *mpcf_input_nth_free(mpc_input_t *i, int n, mpc_val_t **xs, int x) { + int j; + for (j = 0; j < n; j++) { if (j != x) { mpc_free(i, xs[j]); } } + return xs[x]; +} + +static mpc_val_t *mpcf_input_fst_free(mpc_input_t *i, int n, mpc_val_t **xs) { return mpcf_input_nth_free(i, n, xs, 0); } +static mpc_val_t *mpcf_input_snd_free(mpc_input_t *i, int n, mpc_val_t **xs) { return mpcf_input_nth_free(i, n, xs, 1); } +static mpc_val_t *mpcf_input_trd_free(mpc_input_t *i, int n, mpc_val_t **xs) { return mpcf_input_nth_free(i, n, xs, 2); } + +static mpc_val_t *mpcf_input_strfold(mpc_input_t *i, int n, mpc_val_t **xs) { + int j; + size_t l = 0; + if (n == 0) { return mpc_calloc(i, 1, 1); } + for (j = 0; j < n; j++) { l += strlen(xs[j]); } + xs[0] = mpc_realloc(i, xs[0], l + 1); + for (j = 1; j < n; j++) { strcat(xs[0], xs[j]); mpc_free(i, xs[j]); } + return xs[0]; +} + +static mpc_val_t *mpcf_input_state_ast(mpc_input_t *i, int n, mpc_val_t **xs) { + mpc_state_t *s = ((mpc_state_t**)xs)[0]; + mpc_ast_t *a = ((mpc_ast_t**)xs)[1]; + a = mpc_ast_state(a, *s); + mpc_free(i, s); + (void) n; + return a; +} + +static mpc_val_t *mpc_parse_fold(mpc_input_t *i, mpc_fold_t f, int n, mpc_val_t **xs) { + int j; + if (f == mpcf_null) { return mpcf_null(n, xs); } + if (f == mpcf_fst) { return mpcf_fst(n, xs); } + if (f == mpcf_snd) { return mpcf_snd(n, xs); } + if (f == mpcf_trd) { return mpcf_trd(n, xs); } + if (f == mpcf_fst_free) { return mpcf_input_fst_free(i, n, xs); } + if (f == mpcf_snd_free) { return mpcf_input_snd_free(i, n, xs); } + if (f == mpcf_trd_free) { return mpcf_input_trd_free(i, n, xs); } + if (f == mpcf_strfold) { return mpcf_input_strfold(i, n, xs); } + if (f == mpcf_state_ast) { return mpcf_input_state_ast(i, n, xs); } + for (j = 0; j < n; j++) { xs[j] = mpc_export(i, xs[j]); } + return f(j, xs); +} + +static mpc_val_t *mpcf_input_free(mpc_input_t *i, mpc_val_t *x) { + mpc_free(i, x); + return NULL; +} + +static mpc_val_t *mpcf_input_str_ast(mpc_input_t *i, mpc_val_t *c) { + mpc_ast_t *a = mpc_ast_new("", c); + mpc_free(i, c); + return a; +} + +static mpc_val_t *mpc_parse_apply(mpc_input_t *i, mpc_apply_t f, mpc_val_t *x) { + if (f == mpcf_free) { return mpcf_input_free(i, x); } + if (f == mpcf_str_ast) { return mpcf_input_str_ast(i, x); } + return f(mpc_export(i, x)); +} + +static mpc_val_t *mpc_parse_apply_to(mpc_input_t *i, mpc_apply_to_t f, mpc_val_t *x, mpc_val_t *d) { + return f(mpc_export(i, x), d); +} + +static void mpc_parse_dtor(mpc_input_t *i, mpc_dtor_t d, mpc_val_t *x) { + if (d == free) { mpc_free(i, x); return; } + d(mpc_export(i, x)); +} + +enum { + MPC_PARSE_STACK_MIN = 4 +}; #define MPC_SUCCESS(x) r->output = x; return 1 #define MPC_FAILURE(x) r->error = x; return 0 #define MPC_PRIMITIVE(x) \ if (x) { MPC_SUCCESS(r->output); } \ - else { MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Incorrect Input")); } - -enum { - MPC_PARSE_STACK_MIN = 8 -}; + else { MPC_FAILURE(mpc_err_fail(i, "Incorrect Input")); } int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { @@ -791,43 +983,47 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { /* Other parsers */ - case MPC_TYPE_UNDEFINED: MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Parser Undefined!")); + case MPC_TYPE_UNDEFINED: MPC_FAILURE(mpc_err_fail(i, "Parser Undefined!")); case MPC_TYPE_PASS: MPC_SUCCESS(NULL); - case MPC_TYPE_FAIL: MPC_FAILURE(mpc_err_fail(i->filename, i->state, p->data.fail.m)); + case MPC_TYPE_FAIL: MPC_FAILURE(mpc_err_fail(i, p->data.fail.m)); case MPC_TYPE_LIFT: MPC_SUCCESS(p->data.lift.lf()); case MPC_TYPE_LIFT_VAL: MPC_SUCCESS(p->data.lift.x); - case MPC_TYPE_STATE: MPC_SUCCESS(mpc_state_copy(i->state)); + case MPC_TYPE_STATE: MPC_SUCCESS(mpc_input_state_copy(i)); case MPC_TYPE_ANCHOR: if (mpc_input_anchor(i, p->data.anchor.f)) { MPC_SUCCESS(NULL); } else { - MPC_FAILURE(mpc_err_new(i->filename, i->state, "anchor", mpc_input_peekc(i))); + MPC_FAILURE(mpc_err_new(i, "anchor")); } /* Application Parsers */ - case MPC_TYPE_EXPECT: - if (mpc_parse_input(i, p->data.expect.x, r)) { - MPC_SUCCESS(r->output); - } else { - mpc_err_delete(r->error); - MPC_FAILURE(mpc_err_new(i->filename, i->state, p->data.expect.m, mpc_input_peekc(i))); - } - case MPC_TYPE_APPLY: if (mpc_parse_input(i, p->data.apply.x, r)) { - MPC_SUCCESS(p->data.apply.f(r->output)); + MPC_SUCCESS(mpc_parse_apply(i, p->data.apply.f, r->output)); } else { MPC_FAILURE(r->output); } case MPC_TYPE_APPLY_TO: if (mpc_parse_input(i, p->data.apply_to.x, r)) { - MPC_SUCCESS(p->data.apply_to.f(r->output, p->data.apply_to.d)); + MPC_SUCCESS(mpc_parse_apply_to(i, p->data.apply_to.f, r->output, p->data.apply_to.d)); } else { MPC_FAILURE(r->error); } + + + case MPC_TYPE_EXPECT: + mpc_input_suppress_enable(i); + if (mpc_parse_input(i, p->data.expect.x, r)) { + mpc_input_suppress_disable(i); + MPC_SUCCESS(r->output); + } else { + mpc_err_delete_internal(i, r->error); + mpc_input_suppress_disable(i); + MPC_FAILURE(mpc_err_new(i, p->data.expect.m)); + } case MPC_TYPE_PREDICT: mpc_input_backtrack_disable(i); @@ -845,21 +1041,25 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { case MPC_TYPE_NOT: mpc_input_mark(i); + mpc_input_suppress_enable(i); if (mpc_parse_input(i, p->data.not.x, r)) { mpc_input_rewind(i); - p->data.not.dx(r->output); - MPC_FAILURE(mpc_err_new(i->filename, i->state, "opposite", mpc_input_peekc(i))); + mpc_input_suppress_disable(i); + mpc_parse_dtor(i, p->data.not.dx, r->output); + MPC_FAILURE(mpc_err_new(i, "opposite")); } else { mpc_input_unmark(i); - mpc_err_delete(r->error); + mpc_input_suppress_disable(i); MPC_SUCCESS(p->data.not.lf()); } case MPC_TYPE_MAYBE: + mpc_input_suppress_enable(i); if (mpc_parse_input(i, p->data.not.x, r)) { + mpc_input_suppress_disable(i); MPC_SUCCESS(r->output); } else { - mpc_err_delete(r->error); + mpc_input_suppress_disable(i); MPC_SUCCESS(p->data.not.lf()); } @@ -867,42 +1067,57 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { case MPC_TYPE_MANY: - results = malloc(sizeof(mpc_result_t) * results_slots); + results = results_stk; + mpc_input_suppress_enable(i); while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { j++; - if (j >= results_slots) { + if (j == MPC_PARSE_STACK_MIN) { results_slots = j + j / 2; - results = realloc(results, sizeof(mpc_result_t) * results_slots); + results = mpc_malloc(i, sizeof(mpc_result_t) * results_slots); + memcpy(results, results_stk, sizeof(mpc_result_t) * MPC_PARSE_STACK_MIN); + } else if (j >= results_slots) { + results_slots = j + j / 2; + results = mpc_realloc(i, results, sizeof(mpc_result_t) * results_slots); } } - - mpc_err_delete(results[j].error); - MPC_SUCCESS(p->data.repeat.f(j, (mpc_val_t**)results); free(results)); + mpc_input_suppress_disable(i); + MPC_SUCCESS( + mpc_parse_fold(i, p->data.repeat.f, j, (mpc_val_t**)results); + if (j >= MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); case MPC_TYPE_MANY1: - results = malloc(sizeof(mpc_result_t) * results_slots); + results = results_stk; while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { j++; - if (j >= results_slots) { + if (j == 1) { mpc_input_suppress_enable(i); } + if (j == MPC_PARSE_STACK_MIN) { results_slots = j + j / 2; - results = realloc(results, sizeof(mpc_result_t) * results_slots); + results = mpc_malloc(i, sizeof(mpc_result_t) * results_slots); + memcpy(results, results_stk, sizeof(mpc_result_t) * MPC_PARSE_STACK_MIN); + } else if (j >= results_slots) { + results_slots = j + j / 2; + results = mpc_realloc(i, results, sizeof(mpc_result_t) * results_slots); } } if (j == 0) { - MPC_FAILURE(mpc_err_many1(results[0].error); free(results)); + MPC_FAILURE( + mpc_err_many1(i, results[0].error); + if (j >= MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } else { - mpc_err_delete(results[j].error); - MPC_SUCCESS(p->data.repeat.f(j, (mpc_val_t**)results); free(results)); + mpc_input_suppress_disable(i); + MPC_SUCCESS( + mpc_parse_fold(i, p->data.repeat.f, j, (mpc_val_t**)results); + if (j >= MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } case MPC_TYPE_COUNT: results = p->data.repeat.n > MPC_PARSE_STACK_MIN - ? malloc(sizeof(mpc_result_t) * p->data.repeat.n) + ? mpc_malloc(i, sizeof(mpc_result_t) * p->data.repeat.n) : results_stk; while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { @@ -911,14 +1126,16 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { } if (j == p->data.repeat.n) { - MPC_SUCCESS(p->data.repeat.f(j, (mpc_val_t**)results); - if (p->data.repeat.n > MPC_PARSE_STACK_MIN) { free(results); }); + MPC_SUCCESS( + mpc_parse_fold(i, p->data.repeat.f, j, (mpc_val_t**)results); + if (p->data.repeat.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } else { for (k = 0; k < j; k++) { - p->data.repeat.dx(results[k].output); + mpc_parse_dtor(i, p->data.repeat.dx, results[k].output); } - MPC_FAILURE(mpc_err_count(results[j].error, p->data.repeat.n); - if (p->data.repeat.n > MPC_PARSE_STACK_MIN) { free(results); }); + MPC_FAILURE( + mpc_err_count(i, results[j].error, p->data.repeat.n); + if (p->data.repeat.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } /* Combinatory Parsers */ @@ -928,28 +1145,30 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { if (p->data.or.n == 0) { MPC_SUCCESS(NULL); } results = p->data.or.n > MPC_PARSE_STACK_MIN - ? malloc(sizeof(mpc_result_t) * p->data.or.n) + ? mpc_malloc(i, sizeof(mpc_result_t) * p->data.or.n) : results_stk; for (j = 0; j < p->data.or.n; j++) { if (mpc_parse_input(i, p->data.or.xs[j], &results[j])) { for (k = 0; k < j; k++) { - mpc_err_delete(results[k].error); + mpc_err_delete_internal(i, results[k].error); } - MPC_SUCCESS(results[j].output; - if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); + MPC_SUCCESS( + results[j].output; + if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } } - MPC_FAILURE(mpc_err_or((mpc_err_t**)results, j); - if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); + MPC_FAILURE( + mpc_err_or(i, (mpc_err_t**)results, j); + if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); case MPC_TYPE_AND: if (p->data.and.n == 0) { MPC_SUCCESS(NULL); } results = p->data.or.n > MPC_PARSE_STACK_MIN - ? malloc(sizeof(mpc_result_t) * p->data.or.n) + ? mpc_malloc(i, sizeof(mpc_result_t) * p->data.or.n) : results_stk; mpc_input_mark(i); @@ -957,22 +1176,23 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { if (!mpc_parse_input(i, p->data.and.xs[j], &results[j])) { mpc_input_rewind(i); for (k = 0; k < j; k++) { - p->data.and.dxs[k](results[k].output); + mpc_parse_dtor(i, p->data.and.dxs[k], results[k].output); } - MPC_FAILURE(results[j].error; - if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); + MPC_FAILURE( + results[j].error; + if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } } mpc_input_unmark(i); - - MPC_SUCCESS(p->data.and.f(j, (mpc_val_t**)results); - if (p->data.or.n > MPC_PARSE_STACK_MIN) { free(results); }); + MPC_SUCCESS( + mpc_parse_fold(i, p->data.and.f, j, (mpc_val_t**)results); + if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); /* End */ default: - MPC_FAILURE(mpc_err_fail(i->filename, i->state, "Unknown Parser Type Id!")); + MPC_FAILURE(mpc_err_fail(i, "Unknown Parser Type Id!")); } return 0; @@ -987,6 +1207,11 @@ int mpc_parse(const char *filename, const char *string, mpc_parser_t *p, mpc_res int x; mpc_input_t *i = mpc_input_new_string(filename, string); x = mpc_parse_input(i, p, r); + if (x) { + r->output = mpc_export(i, r->output); + } else { + r->error = mpc_err_export(i, r->error); + } mpc_input_delete(i); return x; } @@ -995,6 +1220,11 @@ int mpc_parse_file(const char *filename, FILE *file, mpc_parser_t *p, mpc_result int x; mpc_input_t *i = mpc_input_new_file(filename, file); x = mpc_parse_input(i, p, r); + if (x) { + r->output = mpc_export(i, r->output); + } else { + r->error = mpc_err_export(i, r->error); + } mpc_input_delete(i); return x; } @@ -1003,6 +1233,11 @@ int mpc_parse_pipe(const char *filename, FILE *pipe, mpc_parser_t *p, mpc_result int x; mpc_input_t *i = mpc_input_new_pipe(filename, pipe); x = mpc_parse_input(i, p, r); + if (x) { + r->output = mpc_export(i, r->output); + } else { + r->error = mpc_err_export(i, r->error); + } mpc_input_delete(i); return x; } @@ -1014,7 +1249,7 @@ int mpc_parse_contents(const char *filename, mpc_parser_t *p, mpc_result_t *r) { if (f == NULL) { r->output = NULL; - r->error = mpc_err_fail(filename, mpc_state_new(), "Unable to open file!"); + r->error = mpc_err_file(filename, "Unable to open file!"); return 0; } @@ -2516,9 +2751,9 @@ mpc_val_t *mpcf_str_ast(mpc_val_t *c) { mpc_val_t *mpcf_state_ast(int n, mpc_val_t **xs) { mpc_state_t *s = ((mpc_state_t**)xs)[0]; mpc_ast_t *a = ((mpc_ast_t**)xs)[1]; + (void)n; a = mpc_ast_state(a, *s); free(s); - (void) n; return a; } @@ -2979,7 +3214,7 @@ static mpc_err_t *mpca_lang_st(mpc_input_t *i, mpca_grammar_st_t *st) { mpc_optimise(Base); if (!mpc_parse_input(i, Lang, &r)) { - e = r.error; + e = mpc_err_export(i, r.error); } else { e = NULL; } @@ -3067,7 +3302,8 @@ mpc_err_t *mpca_lang_contents(int flags, const char *filename, ...) { FILE *f = fopen(filename, "rb"); if (f == NULL) { - return mpc_err_fail(filename, mpc_state_new(), "Unable to open file!"); + err = mpc_err_file(filename, "Unable to open file!"); + return err; } va_start(va, filename); From 227dd442ae86ebfb341464ac6bc62ef26cbefe97 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 15 Nov 2015 17:53:10 +0000 Subject: [PATCH 29/49] Fixed bug in error reporting --- mpc.c | 92 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/mpc.c b/mpc.c index 18e196d..516b47a 100644 --- a/mpc.c +++ b/mpc.c @@ -122,7 +122,7 @@ static mpc_input_t *mpc_input_new_string(const char *filename, const char *strin i->last = '\0'; i->mem_index = 0; - memset(i->mem_full, 0, sizeof(mpc_mem_t) * MPC_INPUT_MEM_NUM); + memset(i->mem_full, 0, sizeof(char) * MPC_INPUT_MEM_NUM); return i; } @@ -150,7 +150,7 @@ static mpc_input_t *mpc_input_new_pipe(const char *filename, FILE *pipe) { i->last = '\0'; i->mem_index = 0; - memset(i->mem_full, 0, sizeof(mpc_mem_t) * MPC_INPUT_MEM_NUM); + memset(i->mem_full, 0, sizeof(char) * MPC_INPUT_MEM_NUM); return i; @@ -178,7 +178,7 @@ static mpc_input_t *mpc_input_new_file(const char *filename, FILE *file) { i->last = '\0'; i->mem_index = 0; - memset(i->mem_full, 0, sizeof(mpc_mem_t) * MPC_INPUT_MEM_NUM); + memset(i->mem_full, 0, sizeof(char) * MPC_INPUT_MEM_NUM); return i; } @@ -204,6 +204,7 @@ static int mpc_mem_ptr(mpc_input_t *i, void *p) { static void *mpc_malloc(mpc_input_t *i, size_t n) { size_t j; char *p; + return malloc(n); if (n > sizeof(mpc_mem_t)) { return malloc(n); } @@ -229,6 +230,7 @@ static void *mpc_calloc(mpc_input_t *i, size_t n, size_t m) { static void mpc_free(mpc_input_t *i, void *p) { size_t j; + free(p); return; if (!mpc_mem_ptr(i, p)) { free(p); return; } j = ((size_t)(((char*)p) - ((char*)i->mem))) / sizeof(mpc_mem_t); i->mem_full[j] = 0; @@ -237,6 +239,7 @@ static void mpc_free(mpc_input_t *i, void *p) { static void *mpc_realloc(mpc_input_t *i, void *p, size_t n) { char *q = NULL; + return realloc(p, n); if (!mpc_mem_ptr(i, p)) { return realloc(p, n); } @@ -262,8 +265,10 @@ static void *mpc_export(mpc_input_t *i, void *p) { static void mpc_input_backtrack_disable(mpc_input_t *i) { i->backtrack--; } static void mpc_input_backtrack_enable(mpc_input_t *i) { i->backtrack++; } +/* static void mpc_input_suppress_disable(mpc_input_t *i) { i->suppress--; } static void mpc_input_suppress_enable(mpc_input_t *i) { i->suppress++; } +*/ static void mpc_input_mark(mpc_input_t *i) { @@ -806,6 +811,13 @@ static mpc_err_t *mpc_err_count(mpc_input_t *i, mpc_err_t *x, int n) { return y; } +static mpc_err_t *mpc_err_merge(mpc_input_t *i, mpc_err_t *x, mpc_err_t *y) { + mpc_err_t *errs[2]; + errs[0] = x; + errs[1] = y; + return mpc_err_or(i, errs, 2); +} + /* ** Parser Type */ @@ -962,7 +974,7 @@ enum { if (x) { MPC_SUCCESS(r->output); } \ else { MPC_FAILURE(mpc_err_fail(i, "Incorrect Input")); } -int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { +int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t **e) { int j = 0, k = 0; mpc_result_t results_stk[MPC_PARSE_STACK_MIN]; @@ -1000,14 +1012,14 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { /* Application Parsers */ case MPC_TYPE_APPLY: - if (mpc_parse_input(i, p->data.apply.x, r)) { + if (mpc_parse_run(i, p->data.apply.x, r, e)) { MPC_SUCCESS(mpc_parse_apply(i, p->data.apply.f, r->output)); } else { MPC_FAILURE(r->output); } case MPC_TYPE_APPLY_TO: - if (mpc_parse_input(i, p->data.apply_to.x, r)) { + if (mpc_parse_run(i, p->data.apply_to.x, r, e)) { MPC_SUCCESS(mpc_parse_apply_to(i, p->data.apply_to.f, r->output, p->data.apply_to.d)); } else { MPC_FAILURE(r->error); @@ -1015,19 +1027,16 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { case MPC_TYPE_EXPECT: - mpc_input_suppress_enable(i); - if (mpc_parse_input(i, p->data.expect.x, r)) { - mpc_input_suppress_disable(i); + if (mpc_parse_run(i, p->data.expect.x, r, e)) { MPC_SUCCESS(r->output); } else { mpc_err_delete_internal(i, r->error); - mpc_input_suppress_disable(i); MPC_FAILURE(mpc_err_new(i, p->data.expect.m)); } case MPC_TYPE_PREDICT: mpc_input_backtrack_disable(i); - if (mpc_parse_input(i, p->data.predict.x, r)) { + if (mpc_parse_run(i, p->data.predict.x, r, e)) { mpc_input_backtrack_enable(i); MPC_SUCCESS(r->output); } else { @@ -1041,25 +1050,21 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { case MPC_TYPE_NOT: mpc_input_mark(i); - mpc_input_suppress_enable(i); - if (mpc_parse_input(i, p->data.not.x, r)) { + if (mpc_parse_run(i, p->data.not.x, r, e)) { mpc_input_rewind(i); - mpc_input_suppress_disable(i); mpc_parse_dtor(i, p->data.not.dx, r->output); MPC_FAILURE(mpc_err_new(i, "opposite")); } else { mpc_input_unmark(i); - mpc_input_suppress_disable(i); + mpc_err_delete_internal(i, r->error); MPC_SUCCESS(p->data.not.lf()); } case MPC_TYPE_MAYBE: - mpc_input_suppress_enable(i); - if (mpc_parse_input(i, p->data.not.x, r)) { - mpc_input_suppress_disable(i); + if (mpc_parse_run(i, p->data.not.x, r, e)) { MPC_SUCCESS(r->output); } else { - mpc_input_suppress_disable(i); + *e = mpc_err_merge(i, *e, r->error); MPC_SUCCESS(p->data.not.lf()); } @@ -1069,8 +1074,7 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { results = results_stk; - mpc_input_suppress_enable(i); - while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { + while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) { j++; if (j == MPC_PARSE_STACK_MIN) { results_slots = j + j / 2; @@ -1081,7 +1085,8 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { results = mpc_realloc(i, results, sizeof(mpc_result_t) * results_slots); } } - mpc_input_suppress_disable(i); + + *e = mpc_err_merge(i, *e, results[j].error); MPC_SUCCESS( mpc_parse_fold(i, p->data.repeat.f, j, (mpc_val_t**)results); if (j >= MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); @@ -1090,9 +1095,8 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { results = results_stk; - while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { + while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) { j++; - if (j == 1) { mpc_input_suppress_enable(i); } if (j == MPC_PARSE_STACK_MIN) { results_slots = j + j / 2; results = mpc_malloc(i, sizeof(mpc_result_t) * results_slots); @@ -1105,10 +1109,10 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { if (j == 0) { MPC_FAILURE( - mpc_err_many1(i, results[0].error); + mpc_err_many1(i, results[j].error); if (j >= MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } else { - mpc_input_suppress_disable(i); + *e = mpc_err_merge(i, *e, results[j].error); MPC_SUCCESS( mpc_parse_fold(i, p->data.repeat.f, j, (mpc_val_t**)results); if (j >= MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); @@ -1120,7 +1124,7 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { ? mpc_malloc(i, sizeof(mpc_result_t) * p->data.repeat.n) : results_stk; - while (mpc_parse_input(i, p->data.repeat.x, &results[j])) { + while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) { j++; if (j == p->data.repeat.n) { break; } } @@ -1149,7 +1153,7 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { : results_stk; for (j = 0; j < p->data.or.n; j++) { - if (mpc_parse_input(i, p->data.or.xs[j], &results[j])) { + if (mpc_parse_run(i, p->data.or.xs[j], &results[j], e)) { for (k = 0; k < j; k++) { mpc_err_delete_internal(i, results[k].error); } @@ -1173,7 +1177,7 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { mpc_input_mark(i); for (j = 0; j < p->data.and.n; j++) { - if (!mpc_parse_input(i, p->data.and.xs[j], &results[j])) { + if (!mpc_parse_run(i, p->data.and.xs[j], &results[j], e)) { mpc_input_rewind(i); for (k = 0; k < j; k++) { mpc_parse_dtor(i, p->data.and.dxs[k], results[k].output); @@ -1203,15 +1207,23 @@ int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { #undef MPC_FAILURE #undef MPC_PRIMITIVE +int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { + int x; + mpc_err_t *e = mpc_err_fail(i, "Unknown Error"); + x = mpc_parse_run(i, p, r, &e); + if (x) { + mpc_err_delete_internal(i, e); + r->output = mpc_export(i, r->output); + } else { + r->error = mpc_err_export(i, mpc_err_merge(i, e, r->error)); + } + return x; +} + int mpc_parse(const char *filename, const char *string, mpc_parser_t *p, mpc_result_t *r) { int x; mpc_input_t *i = mpc_input_new_string(filename, string); x = mpc_parse_input(i, p, r); - if (x) { - r->output = mpc_export(i, r->output); - } else { - r->error = mpc_err_export(i, r->error); - } mpc_input_delete(i); return x; } @@ -1220,11 +1232,6 @@ int mpc_parse_file(const char *filename, FILE *file, mpc_parser_t *p, mpc_result int x; mpc_input_t *i = mpc_input_new_file(filename, file); x = mpc_parse_input(i, p, r); - if (x) { - r->output = mpc_export(i, r->output); - } else { - r->error = mpc_err_export(i, r->error); - } mpc_input_delete(i); return x; } @@ -1233,11 +1240,6 @@ int mpc_parse_pipe(const char *filename, FILE *pipe, mpc_parser_t *p, mpc_result int x; mpc_input_t *i = mpc_input_new_pipe(filename, pipe); x = mpc_parse_input(i, p, r); - if (x) { - r->output = mpc_export(i, r->output); - } else { - r->error = mpc_err_export(i, r->error); - } mpc_input_delete(i); return x; } @@ -3214,7 +3216,7 @@ static mpc_err_t *mpca_lang_st(mpc_input_t *i, mpca_grammar_st_t *st) { mpc_optimise(Base); if (!mpc_parse_input(i, Lang, &r)) { - e = mpc_err_export(i, r.error); + e = r.error; } else { e = NULL; } From 131c8a55d53900b325173787591da9c498c5de5e Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 15 Nov 2015 22:13:13 +0000 Subject: [PATCH 30/49] Added back in some optimisations to error creation --- mpc.c | 74 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/mpc.c b/mpc.c index 516b47a..f34519a 100644 --- a/mpc.c +++ b/mpc.c @@ -204,7 +204,6 @@ static int mpc_mem_ptr(mpc_input_t *i, void *p) { static void *mpc_malloc(mpc_input_t *i, size_t n) { size_t j; char *p; - return malloc(n); if (n > sizeof(mpc_mem_t)) { return malloc(n); } @@ -230,7 +229,6 @@ static void *mpc_calloc(mpc_input_t *i, size_t n, size_t m) { static void mpc_free(mpc_input_t *i, void *p) { size_t j; - free(p); return; if (!mpc_mem_ptr(i, p)) { free(p); return; } j = ((size_t)(((char*)p) - ((char*)i->mem))) / sizeof(mpc_mem_t); i->mem_full[j] = 0; @@ -239,7 +237,6 @@ static void mpc_free(mpc_input_t *i, void *p) { static void *mpc_realloc(mpc_input_t *i, void *p, size_t n) { char *q = NULL; - return realloc(p, n); if (!mpc_mem_ptr(i, p)) { return realloc(p, n); } @@ -265,10 +262,8 @@ static void *mpc_export(mpc_input_t *i, void *p) { static void mpc_input_backtrack_disable(mpc_input_t *i) { i->backtrack--; } static void mpc_input_backtrack_enable(mpc_input_t *i) { i->backtrack++; } -/* static void mpc_input_suppress_disable(mpc_input_t *i) { i->suppress--; } static void mpc_input_suppress_enable(mpc_input_t *i) { i->suppress++; } -*/ static void mpc_input_mark(mpc_input_t *i) { @@ -505,7 +500,8 @@ static int mpc_input_string(mpc_input_t *i, const char *c, char **o) { return 1; } -static int mpc_input_anchor(mpc_input_t* i, int(*f)(char,char)) { +static int mpc_input_anchor(mpc_input_t* i, int(*f)(char,char), char **o) { + *o = NULL; return f(i->last, mpc_input_peekc(i)); } @@ -657,7 +653,7 @@ static mpc_err_t *mpc_err_file(const char *filename, const char *failure) { static void mpc_err_delete_internal(mpc_input_t *i, mpc_err_t *x) { int j; - if (i->suppress) { return; } + if (x == NULL) { return; } for (j = 0; j < x->expected_num; j++) { mpc_free(i, x->expected[j]); } mpc_free(i, x->expected); mpc_free(i, x->filename); @@ -667,7 +663,6 @@ static void mpc_err_delete_internal(mpc_input_t *i, mpc_err_t *x) { static mpc_err_t *mpc_err_export(mpc_input_t *i, mpc_err_t *x) { int j; - if (i->suppress) { return NULL; } for (j = 0; j < x->expected_num; j++) { x->expected[j] = mpc_export(i, x->expected[j]); } @@ -696,25 +691,31 @@ static void mpc_err_add_expected(mpc_input_t *i, mpc_err_t *x, char *expected) { static mpc_err_t *mpc_err_or(mpc_input_t *i, mpc_err_t** x, int n) { - int j, k; + int j, k, fst; mpc_err_t *e; - if (i->suppress) { return NULL; } + fst = -1; + for (j = 0; j < n; j++) { + if (x[j] != NULL) { fst = j; } + } + + if (fst == -1) { return NULL; } e = mpc_malloc(i, sizeof(mpc_err_t)); e->state = mpc_state_invalid(); e->expected_num = 0; e->expected = NULL; e->failure = NULL; - e->filename = mpc_malloc(i, strlen(x[0]->filename)+1); - strcpy(e->filename, x[0]->filename); + e->filename = mpc_malloc(i, strlen(x[fst]->filename)+1); + strcpy(e->filename, x[fst]->filename); for (j = 0; j < n; j++) { + if (x[j] == NULL) { continue; } if (x[j]->state.pos > e->state.pos) { e->state = x[j]->state; } } for (j = 0; j < n; j++) { - + if (x[j] == NULL) { continue; } if (x[j]->state.pos < e->state.pos) { continue; } if (x[j]->failure) { @@ -733,6 +734,7 @@ static mpc_err_t *mpc_err_or(mpc_input_t *i, mpc_err_t** x, int n) { } for (j = 0; j < n; j++) { + if (x[j] == NULL) { continue; } mpc_err_delete_internal(i, x[j]); } @@ -745,7 +747,7 @@ static mpc_err_t *mpc_err_repeat(mpc_input_t *i, mpc_err_t *x, const char *prefi size_t l = 0; char *expect = NULL; - if (i->suppress) { return NULL; } + if (x == NULL) { return NULL; } if (x->expected_num == 0) { expect = mpc_calloc(i, 1, 1); @@ -803,7 +805,6 @@ static mpc_err_t *mpc_err_count(mpc_input_t *i, mpc_err_t *x, int n) { mpc_err_t *y; int digits = n/10 + 1; char *prefix; - if (i->suppress) { return NULL; } prefix = mpc_malloc(i, digits + strlen(" of ") + 1); sprintf(prefix, "%i of ", n); y = mpc_err_repeat(i, x, prefix); @@ -972,9 +973,9 @@ enum { #define MPC_FAILURE(x) r->error = x; return 0 #define MPC_PRIMITIVE(x) \ if (x) { MPC_SUCCESS(r->output); } \ - else { MPC_FAILURE(mpc_err_fail(i, "Incorrect Input")); } + else { MPC_FAILURE(NULL); } -int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t **e) { +static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t **e) { int j = 0, k = 0; mpc_result_t results_stk[MPC_PARSE_STACK_MIN]; @@ -992,7 +993,8 @@ int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t ** case MPC_TYPE_NONEOF: MPC_PRIMITIVE(mpc_input_noneof(i, p->data.string.x, (char**)&r->output)); case MPC_TYPE_SATISFY: MPC_PRIMITIVE(mpc_input_satisfy(i, p->data.satisfy.f, (char**)&r->output)); case MPC_TYPE_STRING: MPC_PRIMITIVE(mpc_input_string(i, p->data.string.x, (char**)&r->output)); - + case MPC_TYPE_ANCHOR: MPC_PRIMITIVE(mpc_input_anchor(i, p->data.anchor.f, (char**)&r->output)); + /* Other parsers */ case MPC_TYPE_UNDEFINED: MPC_FAILURE(mpc_err_fail(i, "Parser Undefined!")); @@ -1002,13 +1004,6 @@ int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t ** case MPC_TYPE_LIFT_VAL: MPC_SUCCESS(p->data.lift.x); case MPC_TYPE_STATE: MPC_SUCCESS(mpc_input_state_copy(i)); - case MPC_TYPE_ANCHOR: - if (mpc_input_anchor(i, p->data.anchor.f)) { - MPC_SUCCESS(NULL); - } else { - MPC_FAILURE(mpc_err_new(i, "anchor")); - } - /* Application Parsers */ case MPC_TYPE_APPLY: @@ -1024,13 +1019,14 @@ int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t ** } else { MPC_FAILURE(r->error); } - case MPC_TYPE_EXPECT: + mpc_input_suppress_enable(i); if (mpc_parse_run(i, p->data.expect.x, r, e)) { + mpc_input_suppress_disable(i); MPC_SUCCESS(r->output); } else { - mpc_err_delete_internal(i, r->error); + mpc_input_suppress_disable(i); MPC_FAILURE(mpc_err_new(i, p->data.expect.m)); } @@ -1050,13 +1046,15 @@ int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t ** case MPC_TYPE_NOT: mpc_input_mark(i); + mpc_input_suppress_enable(i); if (mpc_parse_run(i, p->data.not.x, r, e)) { mpc_input_rewind(i); + mpc_input_suppress_disable(i); mpc_parse_dtor(i, p->data.not.dx, r->output); MPC_FAILURE(mpc_err_new(i, "opposite")); } else { mpc_input_unmark(i); - mpc_err_delete_internal(i, r->error); + mpc_input_suppress_disable(i); MPC_SUCCESS(p->data.not.lf()); } @@ -1154,17 +1152,14 @@ int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t ** for (j = 0; j < p->data.or.n; j++) { if (mpc_parse_run(i, p->data.or.xs[j], &results[j], e)) { - for (k = 0; k < j; k++) { - mpc_err_delete_internal(i, results[k].error); - } - MPC_SUCCESS( - results[j].output; + MPC_SUCCESS(results[j].output; if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); - } + } else { + *e = mpc_err_merge(i, *e, results[j].error); + } } - - MPC_FAILURE( - mpc_err_or(i, (mpc_err_t**)results, j); + + MPC_FAILURE(NULL; if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); case MPC_TYPE_AND: @@ -1182,8 +1177,7 @@ int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t ** for (k = 0; k < j; k++) { mpc_parse_dtor(i, p->data.and.dxs[k], results[k].output); } - MPC_FAILURE( - results[j].error; + MPC_FAILURE(results[j].error; if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } } @@ -1476,7 +1470,7 @@ mpc_parser_t *mpc_anchor(int(*f)(char,char)) { mpc_parser_t *p = mpc_undefined(); p->type = MPC_TYPE_ANCHOR; p->data.anchor.f = f; - return p; + return mpc_expect(p, "anchor"); } mpc_parser_t *mpc_state(void) { From 07fe154100e9f77d608f60fddd2402dc277fc840 Mon Sep 17 00:00:00 2001 From: alpha123 Date: Tue, 17 Nov 2015 15:43:25 -0700 Subject: [PATCH 31/49] Fix a minor README error. Precedence of operators was flipped around in the fold_maths example. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7321a41..120ac94 100644 --- a/README.md +++ b/README.md @@ -686,14 +686,14 @@ mpc_parser_t *Maths = mpc_new("maths"); mpc_define(Expr, mpc_or(2, mpc_and(3, fold_maths, - Factor, mpc_oneof("*/"), Factor, + Factor, mpc_oneof("+-"), Factor, free, free), Factor )); mpc_define(Factor, mpc_or(2, mpc_and(3, fold_maths, - Term, mpc_oneof("+-"), Term, + Term, mpc_oneof("*/"), Term, free, free), Term )); From 3ead545ed82932074c51a5567d6598b88a2d0178 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 13 Dec 2015 13:15:10 +0000 Subject: [PATCH 32/49] Fixed bug in error reporting --- mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpc.c b/mpc.c index f34519a..0d3838a 100644 --- a/mpc.c +++ b/mpc.c @@ -1203,7 +1203,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { int x; - mpc_err_t *e = mpc_err_fail(i, "Unknown Error"); + mpc_err_t *e = mpc_err_new(i, "input"); x = mpc_parse_run(i, p, r, &e); if (x) { mpc_err_delete_internal(i, e); From d9c3a453f2778541ced746651cd0d7556ac8694e Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sun, 13 Dec 2015 13:22:01 +0000 Subject: [PATCH 33/49] State needs to be invalid to avoid input being expected --- mpc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mpc.c b/mpc.c index 0d3838a..a8e7f0a 100644 --- a/mpc.c +++ b/mpc.c @@ -1203,7 +1203,8 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e int mpc_parse_input(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r) { int x; - mpc_err_t *e = mpc_err_new(i, "input"); + mpc_err_t *e = mpc_err_fail(i, "Unknown Error"); + e->state = mpc_state_invalid(); x = mpc_parse_run(i, p, r, &e); if (x) { mpc_err_delete_internal(i, e); From c2908c37bbf44029fbe9ec9f0f2efdedc42b62a9 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 20 Feb 2016 14:44:08 +0000 Subject: [PATCH 34/49] Added copy function --- README.md | 10 ++++++++++ mpc.c | 12 ++++++++++++ mpc.h | 1 + 3 files changed, 23 insertions(+) diff --git a/README.md b/README.md index 120ac94..b918603 100644 --- a/README.md +++ b/README.md @@ -530,6 +530,16 @@ void mpc_cleanup(int n, ...); To ease the task of undefining and then deleting parsers `mpc_cleanup` can be used. It takes `n` parsers as input, and undefines them all, before deleting them all. +* * * + +```c +mpc_parser_t *mpc_copy(mpc_parser_t *a); +``` + +This function makes a copy of a parser `a`. This can be useful when you want to +use a parser as input for some other parsers multiple times without retaining +it. + Library Reference ================= diff --git a/mpc.c b/mpc.c index a8e7f0a..cc0267a 100644 --- a/mpc.c +++ b/mpc.c @@ -1364,6 +1364,18 @@ mpc_parser_t *mpc_new(const char *name) { return p; } +mpc_parser_t *mpc_copy(mpc_parser_t *a) { + mpc_parser_t *p = mpc_undefined(); + p->retained = a->retained; + p->type = a->type; + p->data = a->data; + if (a->name) { + p->name = malloc(strlen(a->name)+1); + strcpy(p->name, a->name); + } + return p; +} + mpc_parser_t *mpc_undefine(mpc_parser_t *p) { mpc_undefine_unretained(p, 1); p->type = MPC_TYPE_UNDEFINED; diff --git a/mpc.h b/mpc.h index a408d09..a9d8a72 100644 --- a/mpc.h +++ b/mpc.h @@ -81,6 +81,7 @@ typedef mpc_val_t*(*mpc_fold_t)(int,mpc_val_t**); */ mpc_parser_t *mpc_new(const char *name); +mpc_parser_t *mpc_copy(mpc_parser_t *a); mpc_parser_t *mpc_define(mpc_parser_t *p, mpc_parser_t *a); mpc_parser_t *mpc_undefine(mpc_parser_t *p); From 4da2ae5febfcce003310a0cd2af810272b3a4fa0 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Thu, 3 Mar 2016 10:34:52 +0000 Subject: [PATCH 35/49] Updated copy function to work properly with larger parsers --- mpc.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++- tests/core.c | 39 +++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/mpc.c b/mpc.c index cc0267a..9e84a47 100644 --- a/mpc.c +++ b/mpc.c @@ -1365,14 +1365,77 @@ mpc_parser_t *mpc_new(const char *name) { } mpc_parser_t *mpc_copy(mpc_parser_t *a) { - mpc_parser_t *p = mpc_undefined(); + int i = 0; + mpc_parser_t *p; + + if (a->retained) { return a; } + + p = mpc_undefined(); p->retained = a->retained; p->type = a->type; p->data = a->data; + if (a->name) { p->name = malloc(strlen(a->name)+1); strcpy(p->name, a->name); } + + switch (a->type) { + + case MPC_TYPE_FAIL: + p->data.fail.m = malloc(strlen(a->data.fail.m)+1); + strcpy(p->data.fail.m, a->data.fail.m); + break; + + case MPC_TYPE_ONEOF: + case MPC_TYPE_NONEOF: + case MPC_TYPE_STRING: + p->data.string.x = malloc(strlen(a->data.string.x)+1); + strcpy(p->data.string.x, a->data.string.x); + break; + + case MPC_TYPE_APPLY: p->data.apply.x = mpc_copy(a->data.apply.x); break; + case MPC_TYPE_APPLY_TO: p->data.apply_to.x = mpc_copy(a->data.apply_to.x); break; + case MPC_TYPE_PREDICT: p->data.predict.x = mpc_copy(a->data.predict.x); break; + + case MPC_TYPE_MAYBE: + case MPC_TYPE_NOT: + p->data.not.x = mpc_copy(a->data.not.x); + break; + + case MPC_TYPE_EXPECT: + p->data.expect.x = mpc_copy(a->data.expect.x); + p->data.expect.m = malloc(strlen(a->data.expect.m)+1); + strcpy(p->data.expect.m, a->data.expect.m); + break; + + case MPC_TYPE_MANY: + case MPC_TYPE_MANY1: + case MPC_TYPE_COUNT: + p->data.repeat.x = mpc_copy(a->data.repeat.x); + break; + + case MPC_TYPE_OR: + p->data.or.xs = malloc(a->data.or.n * sizeof(mpc_parser_t*)); + for (i = 0; i < a->data.or.n; i++) { + p->data.or.xs[i] = mpc_copy(a->data.or.xs[i]); + } + break; + case MPC_TYPE_AND: + p->data.and.xs = malloc(a->data.and.n * sizeof(mpc_parser_t*)); + for (i = 0; i < a->data.and.n; i++) { + p->data.and.xs[i] = mpc_copy(a->data.and.xs[i]); + } + p->data.and.dxs = malloc((a->data.and.n-1) * sizeof(mpc_dtor_t)); + for (i = 0; i < a->data.and.n-1; i++) { + p->data.and.dxs[i] = a->data.and.dxs[i]; + } + break; + + default: break; + } + + return p; } diff --git a/tests/core.c b/tests/core.c index de4a3e6..06d7f71 100644 --- a/tests/core.c +++ b/tests/core.c @@ -114,9 +114,48 @@ void test_repeat(void) { } +void test_copy(void) { + + int success; + mpc_result_t r; + mpc_parser_t* p = mpc_or(2, mpc_char('a'), mpc_char('b')); + mpc_parser_t* q = mpc_and(2, mpcf_strfold, p, mpc_copy(p), free); + + success = mpc_parse("test", "aa", q, &r); + PT_ASSERT(success); + PT_ASSERT_STR_EQ(r.output, "aa"); + free(r.output); + + success = mpc_parse("test", "bb", q, &r); + PT_ASSERT(success); + PT_ASSERT_STR_EQ(r.output, "bb"); + free(r.output); + + success = mpc_parse("test", "ab", q, &r); + PT_ASSERT(success); + PT_ASSERT_STR_EQ(r.output, "ab"); + free(r.output); + + success = mpc_parse("test", "ba", q, &r); + PT_ASSERT(success); + PT_ASSERT_STR_EQ(r.output, "ba"); + free(r.output); + + success = mpc_parse("test", "c", p, &r); + PT_ASSERT(!success); + mpc_err_delete(r.error); + + mpc_delete(mpc_copy(p)); + mpc_delete(mpc_copy(q)); + + mpc_delete(q); + +} + void suite_core(void) { pt_add_test(test_ident, "Test Ident", "Suite Core"); pt_add_test(test_maths, "Test Maths", "Suite Core"); pt_add_test(test_strip, "Test Strip", "Suite Core"); pt_add_test(test_repeat, "Test Repeat", "Suite Core"); + pt_add_test(test_copy, "Test Copy", "Suite Core"); } From 2b643c729baec91d4c51b89135c575dc33d5079a Mon Sep 17 00:00:00 2001 From: petermlm Date: Sun, 17 Apr 2016 00:17:45 +0100 Subject: [PATCH 36/49] Made functions to get child nodes of AST by tag --- mpc.c | 32 ++++++++++++++++++++++++++++++++ mpc.h | 5 +++++ 2 files changed, 37 insertions(+) diff --git a/mpc.c b/mpc.c index 9e84a47..e5c350e 100644 --- a/mpc.c +++ b/mpc.c @@ -2776,6 +2776,38 @@ void mpc_ast_print_to(mpc_ast_t *a, FILE *fp) { mpc_ast_print_depth(a, 0, fp); } +int mpc_ast_get_index(mpc_ast_t *ast, char *tag) { + return mpc_ast_get_index_lb(ast, tag, 0); +} + +int mpc_ast_get_index_lb(mpc_ast_t *ast, char *tag, int lb) { + int i; + + for(i=lb; ichildren_num; i++) { + if(strcmp(ast->children[i]->tag, tag) == 0) { + return i; + } + } + + return -1; +} + +mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, char *tag) { + return mpc_ast_get_child_lb(ast, tag, 0); +} + +mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, char *tag, int lb) { + int i; + + for(i=lb; ichildren_num; i++) { + if(strcmp(ast->children[i]->tag, tag) == 0) { + return ast->children[i]; + } + } + + return NULL; +} + mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) { int i, j; diff --git a/mpc.h b/mpc.h index a9d8a72..02a6b4e 100644 --- a/mpc.h +++ b/mpc.h @@ -276,6 +276,11 @@ void mpc_ast_delete(mpc_ast_t *a); void mpc_ast_print(mpc_ast_t *a); void mpc_ast_print_to(mpc_ast_t *a, FILE *fp); +int mpc_ast_get_index(mpc_ast_t *ast, char *tag); +int mpc_ast_get_index_lb(mpc_ast_t *ast, char *tag, int lb); +mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, char *tag); +mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, char *tag, int lb); + /* ** Warning: This function currently doesn't test for equality of the `state` member! */ From 97d634a708122387a6322e0f908f4b10e4210c87 Mon Sep 17 00:00:00 2001 From: petermlm Date: Sun, 17 Apr 2016 18:43:10 +0100 Subject: [PATCH 37/49] Added const to declarations --- mpc.c | 8 ++++---- mpc.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mpc.c b/mpc.c index e5c350e..6c65255 100644 --- a/mpc.c +++ b/mpc.c @@ -2776,11 +2776,11 @@ void mpc_ast_print_to(mpc_ast_t *a, FILE *fp) { mpc_ast_print_depth(a, 0, fp); } -int mpc_ast_get_index(mpc_ast_t *ast, char *tag) { +int mpc_ast_get_index(mpc_ast_t *ast, const char *tag) { return mpc_ast_get_index_lb(ast, tag, 0); } -int mpc_ast_get_index_lb(mpc_ast_t *ast, char *tag, int lb) { +int mpc_ast_get_index_lb(mpc_ast_t *ast, const char *tag, int lb) { int i; for(i=lb; ichildren_num; i++) { @@ -2792,11 +2792,11 @@ int mpc_ast_get_index_lb(mpc_ast_t *ast, char *tag, int lb) { return -1; } -mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, char *tag) { +mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag) { return mpc_ast_get_child_lb(ast, tag, 0); } -mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, char *tag, int lb) { +mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb) { int i; for(i=lb; ichildren_num; i++) { diff --git a/mpc.h b/mpc.h index 02a6b4e..82ee6ba 100644 --- a/mpc.h +++ b/mpc.h @@ -276,10 +276,10 @@ void mpc_ast_delete(mpc_ast_t *a); void mpc_ast_print(mpc_ast_t *a); void mpc_ast_print_to(mpc_ast_t *a, FILE *fp); -int mpc_ast_get_index(mpc_ast_t *ast, char *tag); -int mpc_ast_get_index_lb(mpc_ast_t *ast, char *tag, int lb); -mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, char *tag); -mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, char *tag, int lb); +int mpc_ast_get_index(mpc_ast_t *ast, const char *tag); +int mpc_ast_get_index_lb(mpc_ast_t *ast, const char *tag, int lb); +mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag); +mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb); /* ** Warning: This function currently doesn't test for equality of the `state` member! From d8243d01f1c5c40f771545839f1d1605cd70d80d Mon Sep 17 00:00:00 2001 From: petermlm Date: Sun, 17 Apr 2016 18:44:24 +0100 Subject: [PATCH 38/49] Added example for tree traversal --- examples/tree_traversal.c | 73 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 examples/tree_traversal.c diff --git a/examples/tree_traversal.c b/examples/tree_traversal.c new file mode 100644 index 0000000..3ec0299 --- /dev/null +++ b/examples/tree_traversal.c @@ -0,0 +1,73 @@ +#include "../mpc.h" + +int main(int argc, char *argv[]) { + + mpc_parser_t *Input = mpc_new("input"); + mpc_parser_t *Node = mpc_new("node"); + mpc_parser_t *Leaf = mpc_new("leaf"); + mpc_ast_t *ast, *tree, *child, *child_sub; + mpc_result_t r; + int index, lb; + + mpca_lang(MPCA_LANG_PREDICTIVE, + " node : '(' ',' /foo/ ',' ')' | ;" + " leaf : /bar/;" + " input : /^/ /$/;", + Node, Leaf, Input, NULL); + + if (argc > 1) { + + if (mpc_parse_contents(argv[1], Input, &r)) { + ast = r.output; + } else { + mpc_err_print(r.error); + mpc_err_delete(r.error); + mpc_cleanup(3, Node, Leaf, Input); + return EXIT_FAILURE; + } + + } else { + + if (mpc_parse_pipe("", stdin, Input, &r)) { + ast = r.output; + } else { + mpc_err_print(r.error); + mpc_err_delete(r.error); + mpc_cleanup(3, Node, Leaf, Input); + return EXIT_FAILURE; + } + + } + + /* Get index or child of tree */ + tree = ast->children[1]; + + index = mpc_ast_get_index(tree, "node|>"); + child = mpc_ast_get_child(tree, "node|>"); + + if(child == NULL) { + mpc_cleanup(3, Node, Leaf, Input); + mpc_ast_delete(ast); + return EXIT_FAILURE; + } + + printf("Index: %d; Child: \"%s\"\n", index, child->tag); + + /* Get multiple indexes or children of trees */ + index = mpc_ast_get_index_lb(child, "node|leaf|regex", 0); + child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", 0); + + while(index != -1) { + printf("-- Index: %d; Child: \"%s\"\n", index, child_sub->tag); + + lb = index + 1; + index = mpc_ast_get_index_lb(child, "node|leaf|regex", lb); + child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", lb); + } + + /* Clean up and return */ + mpc_cleanup(3, Node, Leaf, Input); + mpc_ast_delete(ast); + + return EXIT_SUCCESS; +} From aa17e0723e57e03ca9b9a42e50f9bfeecececb4f Mon Sep 17 00:00:00 2001 From: petermlm Date: Sun, 17 Apr 2016 18:51:04 +0100 Subject: [PATCH 39/49] 2 space indentation --- examples/tree_traversal.c | 106 +++++++++++++++++++------------------- mpc.c | 28 +++++----- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/examples/tree_traversal.c b/examples/tree_traversal.c index 3ec0299..b31f660 100644 --- a/examples/tree_traversal.c +++ b/examples/tree_traversal.c @@ -2,72 +2,72 @@ int main(int argc, char *argv[]) { - mpc_parser_t *Input = mpc_new("input"); - mpc_parser_t *Node = mpc_new("node"); - mpc_parser_t *Leaf = mpc_new("leaf"); - mpc_ast_t *ast, *tree, *child, *child_sub; - mpc_result_t r; - int index, lb; + mpc_parser_t *Input = mpc_new("input"); + mpc_parser_t *Node = mpc_new("node"); + mpc_parser_t *Leaf = mpc_new("leaf"); + mpc_ast_t *ast, *tree, *child, *child_sub; + mpc_result_t r; + int index, lb; - mpca_lang(MPCA_LANG_PREDICTIVE, - " node : '(' ',' /foo/ ',' ')' | ;" - " leaf : /bar/;" - " input : /^/ /$/;", - Node, Leaf, Input, NULL); + mpca_lang(MPCA_LANG_PREDICTIVE, + " node : '(' ',' /foo/ ',' ')' | ;" + " leaf : /bar/;" + " input : /^/ /$/;", + Node, Leaf, Input, NULL); - if (argc > 1) { - - if (mpc_parse_contents(argv[1], Input, &r)) { - ast = r.output; - } else { - mpc_err_print(r.error); - mpc_err_delete(r.error); - mpc_cleanup(3, Node, Leaf, Input); - return EXIT_FAILURE; - } + if (argc > 1) { + if (mpc_parse_contents(argv[1], Input, &r)) { + ast = r.output; } else { - - if (mpc_parse_pipe("", stdin, Input, &r)) { - ast = r.output; - } else { - mpc_err_print(r.error); - mpc_err_delete(r.error); - mpc_cleanup(3, Node, Leaf, Input); - return EXIT_FAILURE; - } - + mpc_err_print(r.error); + mpc_err_delete(r.error); + mpc_cleanup(3, Node, Leaf, Input); + return EXIT_FAILURE; } - /* Get index or child of tree */ - tree = ast->children[1]; + } else { - index = mpc_ast_get_index(tree, "node|>"); - child = mpc_ast_get_child(tree, "node|>"); - - if(child == NULL) { - mpc_cleanup(3, Node, Leaf, Input); - mpc_ast_delete(ast); - return EXIT_FAILURE; + if (mpc_parse_pipe("", stdin, Input, &r)) { + ast = r.output; + } else { + mpc_err_print(r.error); + mpc_err_delete(r.error); + mpc_cleanup(3, Node, Leaf, Input); + return EXIT_FAILURE; } - printf("Index: %d; Child: \"%s\"\n", index, child->tag); + } - /* Get multiple indexes or children of trees */ - index = mpc_ast_get_index_lb(child, "node|leaf|regex", 0); - child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", 0); + /* Get index or child of tree */ + tree = ast->children[1]; - while(index != -1) { - printf("-- Index: %d; Child: \"%s\"\n", index, child_sub->tag); + index = mpc_ast_get_index(tree, "node|>"); + child = mpc_ast_get_child(tree, "node|>"); - lb = index + 1; - index = mpc_ast_get_index_lb(child, "node|leaf|regex", lb); - child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", lb); - } - - /* Clean up and return */ + if(child == NULL) { mpc_cleanup(3, Node, Leaf, Input); mpc_ast_delete(ast); + return EXIT_FAILURE; + } - return EXIT_SUCCESS; + printf("Index: %d; Child: \"%s\"\n", index, child->tag); + + /* Get multiple indexes or children of trees */ + index = mpc_ast_get_index_lb(child, "node|leaf|regex", 0); + child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", 0); + + while(index != -1) { + printf("-- Index: %d; Child: \"%s\"\n", index, child_sub->tag); + + lb = index + 1; + index = mpc_ast_get_index_lb(child, "node|leaf|regex", lb); + child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", lb); + } + + /* Clean up and return */ + mpc_cleanup(3, Node, Leaf, Input); + mpc_ast_delete(ast); + + return EXIT_SUCCESS; } diff --git a/mpc.c b/mpc.c index 6c65255..a305b12 100644 --- a/mpc.c +++ b/mpc.c @@ -2777,35 +2777,35 @@ void mpc_ast_print_to(mpc_ast_t *a, FILE *fp) { } int mpc_ast_get_index(mpc_ast_t *ast, const char *tag) { - return mpc_ast_get_index_lb(ast, tag, 0); + return mpc_ast_get_index_lb(ast, tag, 0); } int mpc_ast_get_index_lb(mpc_ast_t *ast, const char *tag, int lb) { - int i; + int i; - for(i=lb; ichildren_num; i++) { - if(strcmp(ast->children[i]->tag, tag) == 0) { - return i; - } + for(i=lb; ichildren_num; i++) { + if(strcmp(ast->children[i]->tag, tag) == 0) { + return i; } + } - return -1; + return -1; } mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag) { - return mpc_ast_get_child_lb(ast, tag, 0); + return mpc_ast_get_child_lb(ast, tag, 0); } mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb) { - int i; + int i; - for(i=lb; ichildren_num; i++) { - if(strcmp(ast->children[i]->tag, tag) == 0) { - return ast->children[i]; - } + for(i=lb; ichildren_num; i++) { + if(strcmp(ast->children[i]->tag, tag) == 0) { + return ast->children[i]; } + } - return NULL; + return NULL; } mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) { From 9ac854ad5a3b75e35554b769b0b3514a6fa8d9f4 Mon Sep 17 00:00:00 2001 From: petermlm Date: Tue, 19 Apr 2016 22:27:32 +0100 Subject: [PATCH 40/49] Made post order tree traversal --- mpc.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mpc.h | 17 ++++++++++++ 2 files changed, 104 insertions(+) diff --git a/mpc.c b/mpc.c index a305b12..9304f24 100644 --- a/mpc.c +++ b/mpc.c @@ -2808,6 +2808,93 @@ mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb) { return NULL; } +mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast, + mpc_ast_trav_order_t order) +{ + mpc_ast_trav_t *trav, *n_trav; + mpc_ast_t *cnode = ast; + + /* Create the traversal structure */ + trav = malloc(sizeof(mpc_ast_trav_t)); + trav->curr_node = cnode; + trav->parent = NULL; + trav->curr_child = 0; + trav->order = order; + + /* Get start node */ + switch(order) { + case mpc_ast_trav_order_pre: + break; + + case mpc_ast_trav_order_post: + while(cnode->children_num > 0) { + cnode = cnode->children[0]; + + n_trav = malloc(sizeof(mpc_ast_trav_t)); + n_trav->curr_node = cnode; + n_trav->parent = trav; + n_trav->curr_child = 0; + n_trav->order = order; + + trav = n_trav; + } + + break; + } + + return trav; +} + +mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav) { + mpc_ast_trav_t *n_trav, *to_free; + mpc_ast_t *ret = NULL; + int cchild; + + if(*trav == NULL) return NULL; + + switch((*trav)->order) { + case mpc_ast_trav_order_pre: + break; + + case mpc_ast_trav_order_post: + ret = (*trav)->curr_node; + + /* Move up tree to the parent If the parent doesn't have any more + * nodes, then this is the current node. If it does, move down to + * its left most child. Also, free the previous traversal node */ + to_free = *trav; + *trav = (*trav)->parent; + free(to_free); + + if(*trav == NULL) + break; + + /* Next child */ + (*trav)->curr_child++; + + /* If there aren't any more children, this is the next node */ + if((*trav)->curr_child >= (*trav)->curr_node->children_num) { + break; + } + + /* If there are still more children, find the leftmost child from + * this node */ + while((*trav)->curr_node->children_num > 0) { + n_trav = malloc(sizeof(mpc_ast_trav_t)); + + cchild = (*trav)->curr_child; + n_trav->curr_node = (*trav)->curr_node->children[cchild]; + n_trav->parent = *trav; + n_trav->curr_child = 0; + n_trav->order = (*trav)->order; + + *trav = n_trav; + } + } + + return ret; +} + mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) { int i, j; diff --git a/mpc.h b/mpc.h index 82ee6ba..bb6d72a 100644 --- a/mpc.h +++ b/mpc.h @@ -281,6 +281,23 @@ int mpc_ast_get_index_lb(mpc_ast_t *ast, const char *tag, int lb); mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag); mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb); +typedef enum { + mpc_ast_trav_order_pre, + mpc_ast_trav_order_post +} mpc_ast_trav_order_t; + +typedef struct mpc_ast_trav_t { + mpc_ast_t *curr_node; + struct mpc_ast_trav_t *parent; + int curr_child; + mpc_ast_trav_order_t order; +} mpc_ast_trav_t; + +mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast, + mpc_ast_trav_order_t order); + +mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav); + /* ** Warning: This function currently doesn't test for equality of the `state` member! */ From 719ca68b6c3fddf75e6a5399d2e188715b6fb499 Mon Sep 17 00:00:00 2001 From: petermlm Date: Tue, 19 Apr 2016 23:14:00 +0100 Subject: [PATCH 41/49] Implemented pre order ast traversal --- mpc.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mpc.c b/mpc.c index 9304f24..4da4cd8 100644 --- a/mpc.c +++ b/mpc.c @@ -2824,6 +2824,7 @@ mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast, /* Get start node */ switch(order) { case mpc_ast_trav_order_pre: + /* Nothing else is needed for pre order start */ break; case mpc_ast_trav_order_post: @@ -2850,10 +2851,39 @@ mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav) { mpc_ast_t *ret = NULL; int cchild; + /* The end of traversal was reached */ if(*trav == NULL) return NULL; switch((*trav)->order) { case mpc_ast_trav_order_pre: + ret = (*trav)->curr_node; + + /* If there aren't any more children, go up */ + while(*trav != NULL && + (*trav)->curr_child >= (*trav)->curr_node->children_num) + { + to_free = *trav; + *trav = (*trav)->parent; + free(to_free); + } + + /* If trav is NULL, the end was reached */ + if(*trav == NULL) { + break; + } + + /* Go to next child */ + n_trav = malloc(sizeof(mpc_ast_trav_t)); + + cchild = (*trav)->curr_child; + n_trav->curr_node = (*trav)->curr_node->children[cchild]; + n_trav->parent = *trav; + n_trav->curr_child = 0; + n_trav->order = (*trav)->order; + + (*trav)->curr_child++; + *trav = n_trav; + break; case mpc_ast_trav_order_post: From e99b35796c4bced28019751e6a473c31f04811f7 Mon Sep 17 00:00:00 2001 From: petermlm Date: Tue, 19 Apr 2016 23:21:39 +0100 Subject: [PATCH 42/49] Made example for tree traversal --- examples/tree_traversal.c | 29 ++++++++++++++++++++++++++++- mpc.c | 8 ++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/examples/tree_traversal.c b/examples/tree_traversal.c index b31f660..7553cdd 100644 --- a/examples/tree_traversal.c +++ b/examples/tree_traversal.c @@ -5,7 +5,8 @@ int main(int argc, char *argv[]) { mpc_parser_t *Input = mpc_new("input"); mpc_parser_t *Node = mpc_new("node"); mpc_parser_t *Leaf = mpc_new("leaf"); - mpc_ast_t *ast, *tree, *child, *child_sub; + mpc_ast_t *ast, *tree, *child, *child_sub, *ast_next; + mpc_ast_trav_t *trav; mpc_result_t r; int index, lb; @@ -65,6 +66,32 @@ int main(int argc, char *argv[]) { child_sub = mpc_ast_get_child_lb(child, "node|leaf|regex", lb); } + /* Traversal */ + printf("Pre order tree traversal.\n"); + trav = mpc_ast_traverse_start(ast, mpc_ast_trav_order_pre); + + ast_next = mpc_ast_traverse_next(&trav); + + while(ast_next != NULL) { + printf("Tag: %s; Contents: %s\n", + ast_next->tag, + ast_next->contents); + ast_next = mpc_ast_traverse_next(&trav); + } + + printf("Post order tree traversal.\n"); + + trav = mpc_ast_traverse_start(ast, mpc_ast_trav_order_post); + + ast_next = mpc_ast_traverse_next(&trav); + + while(ast_next != NULL) { + printf("Tag: %s; Contents: %s\n", + ast_next->tag, + ast_next->contents); + ast_next = mpc_ast_traverse_next(&trav); + } + /* Clean up and return */ mpc_cleanup(3, Node, Leaf, Input); mpc_ast_delete(ast); diff --git a/mpc.c b/mpc.c index 4da4cd8..cbfbcf7 100644 --- a/mpc.c +++ b/mpc.c @@ -2841,6 +2841,10 @@ mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast, } break; + + default: + /* Unreachable, but compiler complaints */ + break; } return trav; @@ -2920,6 +2924,10 @@ mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav) { *trav = n_trav; } + + default: + /* Unreachable, but compiler complaints */ + break; } return ret; From 0037648c49dddffec7cf86f3624486fd577c85a1 Mon Sep 17 00:00:00 2001 From: petermlm Date: Tue, 19 Apr 2016 23:26:20 +0100 Subject: [PATCH 43/49] Identation --- mpc.c | 182 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/mpc.c b/mpc.c index cbfbcf7..29e78c4 100644 --- a/mpc.c +++ b/mpc.c @@ -2811,126 +2811,126 @@ mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb) { mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast, mpc_ast_trav_order_t order) { - mpc_ast_trav_t *trav, *n_trav; - mpc_ast_t *cnode = ast; + mpc_ast_trav_t *trav, *n_trav; + mpc_ast_t *cnode = ast; - /* Create the traversal structure */ - trav = malloc(sizeof(mpc_ast_trav_t)); - trav->curr_node = cnode; - trav->parent = NULL; - trav->curr_child = 0; - trav->order = order; + /* Create the traversal structure */ + trav = malloc(sizeof(mpc_ast_trav_t)); + trav->curr_node = cnode; + trav->parent = NULL; + trav->curr_child = 0; + trav->order = order; - /* Get start node */ - switch(order) { - case mpc_ast_trav_order_pre: - /* Nothing else is needed for pre order start */ - break; + /* Get start node */ + switch(order) { + case mpc_ast_trav_order_pre: + /* Nothing else is needed for pre order start */ + break; - case mpc_ast_trav_order_post: - while(cnode->children_num > 0) { - cnode = cnode->children[0]; + case mpc_ast_trav_order_post: + while(cnode->children_num > 0) { + cnode = cnode->children[0]; - n_trav = malloc(sizeof(mpc_ast_trav_t)); - n_trav->curr_node = cnode; - n_trav->parent = trav; - n_trav->curr_child = 0; - n_trav->order = order; + n_trav = malloc(sizeof(mpc_ast_trav_t)); + n_trav->curr_node = cnode; + n_trav->parent = trav; + n_trav->curr_child = 0; + n_trav->order = order; - trav = n_trav; - } + trav = n_trav; + } - break; + break; - default: - /* Unreachable, but compiler complaints */ - break; - } + default: + /* Unreachable, but compiler complaints */ + break; + } - return trav; + return trav; } mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav) { - mpc_ast_trav_t *n_trav, *to_free; - mpc_ast_t *ret = NULL; - int cchild; + mpc_ast_trav_t *n_trav, *to_free; + mpc_ast_t *ret = NULL; + int cchild; - /* The end of traversal was reached */ - if(*trav == NULL) return NULL; + /* The end of traversal was reached */ + if(*trav == NULL) return NULL; - switch((*trav)->order) { - case mpc_ast_trav_order_pre: - ret = (*trav)->curr_node; + switch((*trav)->order) { + case mpc_ast_trav_order_pre: + ret = (*trav)->curr_node; - /* If there aren't any more children, go up */ - while(*trav != NULL && - (*trav)->curr_child >= (*trav)->curr_node->children_num) - { - to_free = *trav; - *trav = (*trav)->parent; - free(to_free); - } + /* If there aren't any more children, go up */ + while(*trav != NULL && + (*trav)->curr_child >= (*trav)->curr_node->children_num) + { + to_free = *trav; + *trav = (*trav)->parent; + free(to_free); + } - /* If trav is NULL, the end was reached */ - if(*trav == NULL) { - break; - } + /* If trav is NULL, the end was reached */ + if(*trav == NULL) { + break; + } - /* Go to next child */ - n_trav = malloc(sizeof(mpc_ast_trav_t)); + /* Go to next child */ + n_trav = malloc(sizeof(mpc_ast_trav_t)); - cchild = (*trav)->curr_child; - n_trav->curr_node = (*trav)->curr_node->children[cchild]; - n_trav->parent = *trav; - n_trav->curr_child = 0; - n_trav->order = (*trav)->order; + cchild = (*trav)->curr_child; + n_trav->curr_node = (*trav)->curr_node->children[cchild]; + n_trav->parent = *trav; + n_trav->curr_child = 0; + n_trav->order = (*trav)->order; - (*trav)->curr_child++; - *trav = n_trav; + (*trav)->curr_child++; + *trav = n_trav; - break; + break; - case mpc_ast_trav_order_post: - ret = (*trav)->curr_node; + case mpc_ast_trav_order_post: + ret = (*trav)->curr_node; - /* Move up tree to the parent If the parent doesn't have any more - * nodes, then this is the current node. If it does, move down to - * its left most child. Also, free the previous traversal node */ - to_free = *trav; - *trav = (*trav)->parent; - free(to_free); + /* Move up tree to the parent If the parent doesn't have any more nodes, + * then this is the current node. If it does, move down to its left most + * child. Also, free the previous traversal node */ + to_free = *trav; + *trav = (*trav)->parent; + free(to_free); - if(*trav == NULL) - break; + if(*trav == NULL) + break; - /* Next child */ - (*trav)->curr_child++; + /* Next child */ + (*trav)->curr_child++; - /* If there aren't any more children, this is the next node */ - if((*trav)->curr_child >= (*trav)->curr_node->children_num) { - break; - } + /* If there aren't any more children, this is the next node */ + if((*trav)->curr_child >= (*trav)->curr_node->children_num) { + break; + } - /* If there are still more children, find the leftmost child from - * this node */ - while((*trav)->curr_node->children_num > 0) { - n_trav = malloc(sizeof(mpc_ast_trav_t)); + /* If there are still more children, find the leftmost child from this + * node */ + while((*trav)->curr_node->children_num > 0) { + n_trav = malloc(sizeof(mpc_ast_trav_t)); - cchild = (*trav)->curr_child; - n_trav->curr_node = (*trav)->curr_node->children[cchild]; - n_trav->parent = *trav; - n_trav->curr_child = 0; - n_trav->order = (*trav)->order; + cchild = (*trav)->curr_child; + n_trav->curr_node = (*trav)->curr_node->children[cchild]; + n_trav->parent = *trav; + n_trav->curr_child = 0; + n_trav->order = (*trav)->order; - *trav = n_trav; - } + *trav = n_trav; + } - default: - /* Unreachable, but compiler complaints */ - break; - } + default: + /* Unreachable, but compiler complaints */ + break; + } - return ret; + return ret; } mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) { From 0b287e6252cddbe317185c898fba219c43fa01de Mon Sep 17 00:00:00 2001 From: petermlm Date: Tue, 19 Apr 2016 23:26:52 +0100 Subject: [PATCH 44/49] Indentation --- mpc.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mpc.h b/mpc.h index bb6d72a..1ac123a 100644 --- a/mpc.h +++ b/mpc.h @@ -282,15 +282,15 @@ mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag); mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb); typedef enum { - mpc_ast_trav_order_pre, - mpc_ast_trav_order_post + mpc_ast_trav_order_pre, + mpc_ast_trav_order_post } mpc_ast_trav_order_t; typedef struct mpc_ast_trav_t { - mpc_ast_t *curr_node; - struct mpc_ast_trav_t *parent; - int curr_child; - mpc_ast_trav_order_t order; + mpc_ast_t *curr_node; + struct mpc_ast_trav_t *parent; + int curr_child; + mpc_ast_trav_order_t order; } mpc_ast_trav_t; mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast, From 258cf5002b9139086bd882d52d1fd582754df814 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 4 May 2016 10:14:59 +0530 Subject: [PATCH 45/49] .gitignore examples/tree_traversal --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 40be4fa..a82e7ec 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ examples/lispy examples/maths examples/smallc examples/foobar +examples/tree_traversal From e032b410b2a74578c9865dddcd9f1f826133082a Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 4 May 2016 10:32:02 +0530 Subject: [PATCH 46/49] Remove foobar and tree_traversal too while doing 'make clean' --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4f3cca0..9a45c77 100644 --- a/Makefile +++ b/Makefile @@ -20,4 +20,5 @@ examples/%: examples/%.c mpc.c $(CC) $(CFLAGS) $^ -lm -o $@ clean: - rm -rf test examples/doge examples/lispy examples/maths examples/smallc + rm -rf test examples/doge examples/lispy examples/maths examples/smallc \ + examples/foobar examples/tree_traversal From 913cc5882449b5016f4db07edbd8566dc877b389 Mon Sep 17 00:00:00 2001 From: petermlm Date: Tue, 31 May 2016 22:32:24 +0100 Subject: [PATCH 47/49] Made traversal free --- examples/tree_traversal.c | 21 ++++++++++++++++++++- mpc.c | 11 +++++++++++ mpc.h | 2 ++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/examples/tree_traversal.c b/examples/tree_traversal.c index 7553cdd..88a5537 100644 --- a/examples/tree_traversal.c +++ b/examples/tree_traversal.c @@ -8,7 +8,7 @@ int main(int argc, char *argv[]) { mpc_ast_t *ast, *tree, *child, *child_sub, *ast_next; mpc_ast_trav_t *trav; mpc_result_t r; - int index, lb; + int index, lb, i; mpca_lang(MPCA_LANG_PREDICTIVE, " node : '(' ',' /foo/ ',' ')' | ;" @@ -79,6 +79,8 @@ int main(int argc, char *argv[]) { ast_next = mpc_ast_traverse_next(&trav); } + mpc_ast_traverse_free(&trav); + printf("Post order tree traversal.\n"); trav = mpc_ast_traverse_start(ast, mpc_ast_trav_order_post); @@ -92,6 +94,23 @@ int main(int argc, char *argv[]) { ast_next = mpc_ast_traverse_next(&trav); } + mpc_ast_traverse_free(&trav); + + printf("Partial traversal.\n"); + + trav = mpc_ast_traverse_start(ast, mpc_ast_trav_order_post); + + ast_next = mpc_ast_traverse_next(&trav); + + for(i=0; i<2 && ast_next != NULL; i++) { + printf("Tag: %s; Contents: %s\n", + ast_next->tag, + ast_next->contents); + ast_next = mpc_ast_traverse_next(&trav); + } + + mpc_ast_traverse_free(&trav); + /* Clean up and return */ mpc_cleanup(3, Node, Leaf, Input); mpc_ast_delete(ast); diff --git a/mpc.c b/mpc.c index 29e78c4..cba873f 100644 --- a/mpc.c +++ b/mpc.c @@ -2933,6 +2933,17 @@ mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav) { return ret; } +void mpc_ast_traverse_free(mpc_ast_trav_t **trav) { + mpc_ast_trav_t *n_trav; + + /* Go through parents until all are free */ + while(*trav != NULL) { + n_trav = (*trav)->parent; + free(*trav); + *trav = n_trav; + } +} + mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) { int i, j; diff --git a/mpc.h b/mpc.h index 1ac123a..5dec3af 100644 --- a/mpc.h +++ b/mpc.h @@ -298,6 +298,8 @@ mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast, mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav); +void mpc_ast_traverse_free(mpc_ast_trav_t **trav); + /* ** Warning: This function currently doesn't test for equality of the `state` member! */ From 14001ad33269a3e36222dcd761df1d2889717789 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 11 Jun 2016 12:59:55 +0100 Subject: [PATCH 48/49] Added test for partial grammar definition --- mpc.c | 4 ++-- tests/grammar.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/mpc.c b/mpc.c index cba873f..e2b58ba 100644 --- a/mpc.c +++ b/mpc.c @@ -2095,7 +2095,7 @@ static mpc_val_t *mpcf_re_range(mpc_val_t *x) { for (j = start; j <= end; j++) { range = realloc(range, strlen(range) + 1 + 1 + 1); range[strlen(range) + 1] = '\0'; - range[strlen(range) + 0] = j; + range[strlen(range) + 0] = (char)j; } } } @@ -2217,7 +2217,7 @@ mpc_val_t *mpcf_oct(mpc_val_t *x) { mpc_val_t *mpcf_float(mpc_val_t *x) { float *y = malloc(sizeof(float)); - *y = strtod(x, NULL); + *y = strtof(x, NULL); free(x); return y; } diff --git a/tests/grammar.c b/tests/grammar.c index b1cd2e5..069e28a 100644 --- a/tests/grammar.c +++ b/tests/grammar.c @@ -128,9 +128,49 @@ void test_doge(void) { } +void test_partial(void) { + + mpc_ast_t *t0; + mpc_err_t *err; + + mpc_parser_t *Line = mpc_new("line"); + mpc_parser_t *Number = mpc_new("number"); + mpc_parser_t *QuotedString = mpc_new("quoted_string"); + mpc_parser_t *LinePragma = mpc_new("linepragma"); + mpc_parser_t *Parser = mpc_new("parser"); + + mpc_define(Line, mpca_tag(mpc_apply(mpc_sym("#line"), mpcf_str_ast), "string")); + + err = mpca_lang(MPCA_LANG_PREDICTIVE, + "number : /[0-9]+/ ;\n" + "quoted_string : /\"(\\.|[^\"])*\"/ ;\n" + "linepragma : ;\n" + "parser : /^/ ()* /$/ ;\n", + Line, Number, QuotedString, LinePragma, Parser, NULL); + + PT_ASSERT(err == NULL); + + t0 = mpc_ast_build(3, ">", + mpc_ast_new("regex", ""), + mpc_ast_build(3, "linepragma|>", + mpc_ast_new("line|string", "#line"), + mpc_ast_new("number|regex", "10"), + mpc_ast_new("quoted_string|regex", "\"test\"")), + mpc_ast_new("regex", "")); + + PT_ASSERT(mpc_test_pass(Parser, "#line 10 \"test\"", t0, + (int(*)(const void*,const void*))mpc_ast_eq, + (mpc_dtor_t)mpc_ast_delete, + (void(*)(const void*))mpc_ast_print)); + + mpc_cleanup(5, Line, Number, QuotedString, LinePragma, Parser); + +} + void suite_grammar(void) { pt_add_test(test_grammar, "Test Grammar", "Suite Grammar"); pt_add_test(test_language, "Test Language", "Suite Grammar"); pt_add_test(test_language_file, "Test Language File", "Suite Grammar"); pt_add_test(test_doge, "Test Doge", "Suite Grammar"); + pt_add_test(test_partial, "Test Partial", "Suite Grammar"); } From 2a19e4c45161f99dee7f1a378b3e4d11e2af7162 Mon Sep 17 00:00:00 2001 From: Daniel Holden Date: Sat, 11 Jun 2016 14:11:19 +0100 Subject: [PATCH 49/49] Fixed folding of single child asts with tags --- README.md | 2 +- mpc.c | 20 +++++++---- mpc.h | 1 + package.json | 2 +- tests/grammar.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 106 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b918603..be6322a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Micro Parser Combinators ======================== -Version 0.8.7 +Version 0.8.8 About diff --git a/mpc.c b/mpc.c index e2b58ba..1801606 100644 --- a/mpc.c +++ b/mpc.c @@ -2730,6 +2730,14 @@ mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t) { return a; } +mpc_ast_t *mpc_ast_add_root_tag(mpc_ast_t *a, const char *t) { + if (a == NULL) { return a; } + a->tag = realloc(a->tag, (strlen(t)-1) + strlen(a->tag) + 1); + memmove(a->tag + (strlen(t)-1), a->tag, strlen(a->tag)+1); + memmove(a->tag, t, (strlen(t)-1)); + return a; +} + mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t) { a->tag = realloc(a->tag, strlen(t) + 1); strcpy(a->tag, t); @@ -2961,16 +2969,16 @@ mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **xs) { if (as[i] == NULL) { continue; } - if (as[i] && as[i]->children_num > 0) { - + if (as[i] && as[i]->children_num == 0) { + mpc_ast_add_child(r, as[i]); + } else if (as[i] && as[i]->children_num == 1) { + mpc_ast_add_child(r, mpc_ast_add_root_tag(as[i]->children[0], as[i]->tag)); + mpc_ast_delete_no_children(as[i]); + } else if (as[i] && as[i]->children_num >= 2) { for (j = 0; j < as[i]->children_num; j++) { mpc_ast_add_child(r, as[i]->children[j]); } - mpc_ast_delete_no_children(as[i]); - - } else if (as[i] && as[i]->children_num == 0) { - mpc_ast_add_child(r, as[i]); } } diff --git a/mpc.h b/mpc.h index 5dec3af..9fd678f 100644 --- a/mpc.h +++ b/mpc.h @@ -269,6 +269,7 @@ mpc_ast_t *mpc_ast_build(int n, const char *tag, ...); mpc_ast_t *mpc_ast_add_root(mpc_ast_t *a); mpc_ast_t *mpc_ast_add_child(mpc_ast_t *r, mpc_ast_t *a); mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t); +mpc_ast_t *mpc_ast_add_root_tag(mpc_ast_t *a, const char *t); mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t); mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s); diff --git a/package.json b/package.json index f398f3b..adcb3bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mpc", - "version": "0.8.7", + "version": "0.8.8", "repo": "orangeduck/mpc", "description": "A Parser Combinator library for C", "keywords": ["parser", "combinator", "library", "c", "mpc"], diff --git a/tests/grammar.c b/tests/grammar.c index 069e28a..ddf2824 100644 --- a/tests/grammar.c +++ b/tests/grammar.c @@ -25,7 +25,7 @@ void test_grammar(void) { t2 = mpc_ast_build(3, ">", - mpc_ast_build(3, "value|>", + mpc_ast_build(3, "product|value|>", mpc_ast_new("char", "("), mpc_ast_build(3, "expression|>", @@ -167,10 +167,98 @@ void test_partial(void) { } +void test_qscript(void) { + + mpc_ast_t *t0; + mpc_parser_t *Qscript = mpc_new("qscript"); + mpc_parser_t *Comment = mpc_new("comment"); + mpc_parser_t *Resource = mpc_new("resource"); + mpc_parser_t *Rtype = mpc_new("rtype"); + mpc_parser_t *Rname = mpc_new("rname"); + mpc_parser_t *InnerBlock = mpc_new("inner_block"); + mpc_parser_t *Statement = mpc_new("statement"); + mpc_parser_t *Function = mpc_new("function"); + mpc_parser_t *Parameter = mpc_new("parameter"); + mpc_parser_t *Literal = mpc_new("literal"); + mpc_parser_t *Block = mpc_new("block"); + mpc_parser_t *Seperator = mpc_new("seperator"); + mpc_parser_t *Qstring = mpc_new("qstring"); + mpc_parser_t *SimpleStr = mpc_new("simplestr"); + mpc_parser_t *ComplexStr = mpc_new("complexstr"); + mpc_parser_t *Number = mpc_new("number"); + mpc_parser_t *Float = mpc_new("float"); + mpc_parser_t *Int = mpc_new("int"); + + mpc_err_t *err = mpca_lang(0, + " qscript : /^/ ( | )* /$/ ;\n" + " comment : '#' /[^\\n]*/ ;\n" + "resource : '[' ( ) ']' ;\n" + " rtype : /[*]*/ ;\n" + " rname : ;\n" + "\n" + "inner_block : ( | )* ;\n" + " statement : '(' ( | | )* ')' ;\n" + " function : ;\n" + " parameter : ( | ) ;\n" + " literal : ( | ) ;\n" + " block : '{' '}' ;\n" + " seperator : ',' | \"\" ;\n" + "\n" + "qstring : ( | ) * ;\n" + " simplestr : /[a-zA-Z0-9_!@#$%^&\\*_+\\-\\.=\\/<>]+/ ;\n" + " complexstr : (/\"[^\"]*\"/ | /'[^']*'/) ;\n" + "\n" + "number : ( | ) ;\n" + " float : /[-+]?[0-9]+\\.[0-9]+/ ;\n" + " int : /[-+]?[0-9]+/ ;\n", + Qscript, Comment, Resource, Rtype, Rname, InnerBlock, Statement, Function, + Parameter, Literal, Block, Seperator, Qstring, SimpleStr, ComplexStr, Number, + Float, Int, NULL); + + PT_ASSERT(err == NULL); + + t0 = mpc_ast_build(3, ">", + mpc_ast_new("regex", ""), + mpc_ast_build(5, "resource|>", + mpc_ast_new("char", "["), + mpc_ast_new("rtype|regex", ""), + mpc_ast_new("rname|qstring|simplestr|regex", "my_func"), + mpc_ast_new("char", "]"), + mpc_ast_build(5, "inner_block|statement|>", + mpc_ast_new("function|qstring|simplestr|regex", "echo"), + mpc_ast_new("char", "("), + mpc_ast_build(2, "parameter|literal|>", + mpc_ast_build(2, "qstring|>", + mpc_ast_new("simplestr|regex", "a"), + mpc_ast_build(2, "qstring|>", + mpc_ast_new("simplestr|regex", "b"), + mpc_ast_new("qstring|simplestr|regex", "c") + ) + ), + mpc_ast_new("seperator|string", "") + ), + mpc_ast_new("char", ")"), + mpc_ast_new("seperator|string", "") + ) + ), + mpc_ast_new("regex", "")); + + PT_ASSERT(mpc_test_pass(Qscript, "[my_func]\n echo (a b c)\n", t0, + (int(*)(const void*,const void*))mpc_ast_eq, + (mpc_dtor_t)mpc_ast_delete, + (void(*)(const void*))mpc_ast_print)); + + mpc_cleanup(18, Qscript, Comment, Resource, Rtype, Rname, InnerBlock, + Statement, Function, Parameter, Literal, Block, Seperator, Qstring, + SimpleStr, ComplexStr, Number, Float, Int); + +} + void suite_grammar(void) { pt_add_test(test_grammar, "Test Grammar", "Suite Grammar"); pt_add_test(test_language, "Test Language", "Suite Grammar"); pt_add_test(test_language_file, "Test Language File", "Suite Grammar"); pt_add_test(test_doge, "Test Doge", "Suite Grammar"); pt_add_test(test_partial, "Test Partial", "Suite Grammar"); + pt_add_test(test_qscript, "Test QScript", "Suite Grammar"); }