diff --git a/.gitignore b/.gitignore index 14a8995..a82e7ec 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,9 @@ *.exe *.dSYM test -doge -lispy -maths -smallc +examples/doge +examples/lispy +examples/maths +examples/smallc +examples/foobar +examples/tree_traversal 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/Makefile b/Makefile index acac791..9a45c77 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 -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 TESTS = $(wildcard tests/*.c) EXAMPLES = $(wildcard examples/*.c) @@ -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 diff --git a/README.md b/README.md index f8a46e6..be6322a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Micro Parser Combinators ======================== -Version 0.8.5 +Version 0.8.8 About @@ -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 ================= @@ -555,9 +565,9 @@ 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_alphaMatches any alphabet character mpc_underscoreMatches '_' mpc_alphanumMatches any alphabet character, underscore or digit mpc_intMatches digits and returns an int* @@ -582,22 +592,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 "]" @@ -623,7 +633,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 @@ -684,14 +696,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 )); @@ -784,6 +796,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/foobar.c b/examples/foobar.c new file mode 100644 index 0000000..983974d --- /dev/null +++ b/examples/foobar.c @@ -0,0 +1,28 @@ +#include "../mpc.h" + +int main(int argc, char** argv) { + + mpc_result_t r; + mpc_parser_t* Foobar; + + if (argc != 2) { + printf("Usage: ./foobar \n"); + exit(0); + } + + Foobar = mpc_new("foobar"); + mpca_lang(MPCA_LANG_DEFAULT, "foobar : \"foo\" | \"bar\";", Foobar); + + if (mpc_parse("", argv[1], Foobar, &r)) { + mpc_ast_print(r.output); + mpc_ast_delete(r.output); + } else { + mpc_err_print(r.error); + mpc_err_delete(r.error); + } + + mpc_cleanup(1, Foobar); + + return 0; +} + diff --git a/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/examples/tree_traversal.c b/examples/tree_traversal.c new file mode 100644 index 0000000..88a5537 --- /dev/null +++ b/examples/tree_traversal.c @@ -0,0 +1,119 @@ +#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, *ast_next; + mpc_ast_trav_t *trav; + mpc_result_t r; + int index, lb, i; + + 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); + } + + /* 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); + } + + mpc_ast_traverse_free(&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); + } + + 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); + + return EXIT_SUCCESS; +} diff --git a/mpc.c b/mpc.c index 963ec9b..535830a 100644 --- a/mpc.c +++ b/mpc.c @@ -20,257 +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[3]; - -static const char *mpc_err_char_unescape(char c) { - - char_unescape_buffer[0] = '\''; - char_unescape_buffer[1] = ' '; - char_unescape_buffer[2] = '\''; - - 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) { - - char *buffer = calloc(1, 1024); - int max = 1023; - int pos = 0; - int i; - - 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 */ @@ -312,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; @@ -322,13 +83,19 @@ 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; static mpc_input_t *mpc_input_new_string(const char *filename, const char *string) { @@ -346,13 +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 = 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'; + i->mem_index = 0; + memset(i->mem_full, 0, sizeof(char) * MPC_INPUT_MEM_NUM); + return i; } @@ -395,13 +166,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 = 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'; + i->mem_index = 0; + memset(i->mem_full, 0, sizeof(char) * MPC_INPUT_MEM_NUM); + return i; } @@ -419,13 +194,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 = 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'; + i->mem_index = 0; + memset(i->mem_full, 0, sizeof(char) * MPC_INPUT_MEM_NUM); + return i; } @@ -441,16 +220,88 @@ 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; } 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; @@ -465,8 +316,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); @@ -587,10 +445,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; @@ -606,7 +462,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'; } @@ -652,14 +508,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; } @@ -667,15 +520,330 @@ 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; } -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)); } +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 (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); + 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; + 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, fst; + mpc_err_t *e; + + 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[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) { + 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++) { + if (x[j] == NULL) { continue; } + 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 (x == NULL) { 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; + 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; +} + +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 */ @@ -752,456 +920,325 @@ struct mpc_parser_t { mpc_pdata_t data; }; -/* -** Stack Type -*/ +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); } -typedef struct { +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]; +} - int parsers_num; - int parsers_slots; - mpc_parser_t **parsers; - int *states; +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; +} - int results_num; - int results_slots; +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(NULL); } + +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]; mpc_result_t *results; - int *returns; + int results_slots = MPC_PARSE_STACK_MIN; - mpc_err_t *err; - -} mpc_stack_t; + switch (p->type) { + + /* Basic Parsers */ -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->results_num = 0; - s->results_slots = 0; - s->results = NULL; - s->returns = NULL; - - 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 = ceil((s->parsers_slots+1) * 1.5); - 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)); - 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 = ceil((s->results_slots + 1) * 1.5); - 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)); - 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. -** -** 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. -** -** 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_PRIMATIVE(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) { - - /* 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; - - /* Go! */ - mpc_stack_pushp(stk, init); - - while (!mpc_stack_empty(stk)) { + 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)); + case MPC_TYPE_ANCHOR: MPC_PRIMITIVE(mpc_input_anchor(i, p->data.anchor.f, (char**)&r->output)); - mpc_stack_peepp(stk, &p, &st); + /* Other parsers */ - switch (p->type) { + 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, 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_input_state_copy(i)); + + /* Application Parsers */ + + case MPC_TYPE_APPLY: + 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_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); + } + + 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_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_run(i, p->data.predict.x, r, e)) { + 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); + 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_input_suppress_disable(i); + MPC_SUCCESS(p->data.not.lf()); + } + + case MPC_TYPE_MAYBE: + if (mpc_parse_run(i, p->data.not.x, r, e)) { + MPC_SUCCESS(r->output); + } else { + *e = mpc_err_merge(i, *e, r->error); + MPC_SUCCESS(p->data.not.lf()); + } + + /* Repeat Parsers */ + + case MPC_TYPE_MANY: - /* 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)); + results = results_stk; - /* Other parsers */ + while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) { + j++; + if (j == MPC_PARSE_STACK_MIN) { + results_slots = j + j / 2; + 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); + } + } - 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)); + *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); }); + + case MPC_TYPE_MANY1: - case MPC_TYPE_ANCHOR: - if (mpc_input_anchor(i, p->data.anchor.f)) { - MPC_SUCCESS(NULL); + results = results_stk; + + while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) { + j++; + if (j == MPC_PARSE_STACK_MIN) { + results_slots = j + j / 2; + 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(i, results[j].error); + if (j >= MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); + } else { + *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); }); + } + + case MPC_TYPE_COUNT: + + results = p->data.repeat.n > MPC_PARSE_STACK_MIN + ? mpc_malloc(i, sizeof(mpc_result_t) * p->data.repeat.n) + : results_stk; + + while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) { + j++; + if (j == p->data.repeat.n) { break; } + } + + if (j == p->data.repeat.n) { + 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++) { + mpc_parse_dtor(i, p->data.repeat.dx, results[k].output); + } + 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 */ + + case MPC_TYPE_OR: + + if (p->data.or.n == 0) { MPC_SUCCESS(NULL); } + + results = p->data.or.n > MPC_PARSE_STACK_MIN + ? 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_run(i, p->data.or.xs[j], &results[j], e)) { + MPC_SUCCESS(results[j].output; + if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } else { - MPC_FAILURE(mpc_err_new(i->filename, i->state, "anchor", mpc_input_peekc(i))); - } + *e = mpc_err_merge(i, *e, results[j].error); + } + } - /* Application Parsers */ + MPC_FAILURE(NULL; + if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); + + case MPC_TYPE_AND: - 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))); + if (p->data.and.n == 0) { MPC_SUCCESS(NULL); } + + results = p->data.or.n > MPC_PARSE_STACK_MIN + ? mpc_malloc(i, sizeof(mpc_result_t) * p->data.or.n) + : results_stk; + + mpc_input_mark(i); + for (j = 0; j < p->data.and.n; 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); } + MPC_FAILURE(results[j].error; + if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); }); } + } + mpc_input_unmark(i); + 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: - 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); - } - } - - 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_CONTINUE(st+1, p->data.repeat.x); - } 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)); - } 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)); - } - } - } - - /* 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.or.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, "Unknown Parser Type Id!")); } - return mpc_stack_terminate(stk, final); + return 0; } -#undef MPC_CONTINUE #undef MPC_SUCCESS #undef MPC_FAILURE -#undef MPC_PRIMATIVE +#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"); + e->state = mpc_state_invalid(); + 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; @@ -1242,7 +1279,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; } @@ -1360,6 +1397,81 @@ mpc_parser_t *mpc_new(const char *name) { return p; } +mpc_parser_t *mpc_copy(mpc_parser_t *a) { + 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; +} + mpc_parser_t *mpc_undefine(mpc_parser_t *p) { mpc_undefine_unretained(p, 1); p->type = MPC_TYPE_UNDEFINED; @@ -1467,7 +1579,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) { @@ -1561,7 +1673,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); } @@ -1978,12 +2090,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] == '^' && @@ -2014,9 +2126,9 @@ 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; + range[strlen(range) + 0] = (char)j; } } } @@ -2082,6 +2194,13 @@ 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); + 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); @@ -2090,8 +2209,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; @@ -2129,12 +2249,33 @@ 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); + float *y = malloc(sizeof(float)); + *y = strtof(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'}; @@ -2156,9 +2297,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) { @@ -2192,10 +2333,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; @@ -2204,7 +2345,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; @@ -2213,9 +2354,9 @@ 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); + y = realloc(y, strlen(y) + 1 + 1); buff[0] = *s; buff[1] = '\0'; strcat(y, buff); } @@ -2240,6 +2381,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); @@ -2288,14 +2435,20 @@ 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; - 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 = 0; + + 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) { @@ -2511,6 +2664,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]); } @@ -2609,6 +2763,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); @@ -2624,6 +2786,12 @@ mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s) { static void mpc_ast_print_depth(mpc_ast_t *a, int d, FILE *fp) { int i; + + if (a == NULL) { + fprintf(fp, "NULL\n"); + return; + } + for (i = 0; i < d; i++) { fprintf(fp, " "); } if (strlen(a->contents)) { @@ -2649,6 +2817,174 @@ 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, const char *tag) { + 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; + + 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, const char *tag) { + 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; + + for(i=lb; ichildren_num; i++) { + if(strcmp(ast->children[i]->tag, tag) == 0) { + return ast->children[i]; + } + } + + 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: + /* Nothing else is needed for pre order start */ + 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; + + default: + /* Unreachable, but compiler complaints */ + 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; + + /* 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: + 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; + } + + default: + /* Unreachable, but compiler complaints */ + break; + } + + 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; @@ -2666,16 +3002,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]); } } @@ -2696,9 +3032,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; } @@ -2989,6 +3325,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); @@ -2999,6 +3341,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; } @@ -3079,12 +3423,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; @@ -3141,6 +3487,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; @@ -3231,7 +3583,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); @@ -3252,3 +3605,220 @@ 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; + + 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) { + t = p->data.and.xs[1]; + mpc_delete(p->data.and.xs[0]); + free(p->data.and.xs); free(p->data.and.dxs); free(p->name); + memcpy(p, t, sizeof(mpc_parser_t)); + free(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 - 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*)); + 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; + } + + /* 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 - 1)); + memmove(p->data.and.xs + n - 1, t->data.and.xs, m * sizeof(mpc_parser_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; + } + + /* 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) { + t = p->data.and.xs[1]; + mpc_delete(p->data.and.xs[0]); + free(p->data.and.xs); free(p->data.and.dxs); free(p->name); + memcpy(p, t, sizeof(mpc_parser_t)); + free(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 - 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*)); + 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; + } + + /* 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 - 1)); + memmove(p->data.and.xs + n - 1, t->data.and.xs, m * sizeof(mpc_parser_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; + } + + return; + + } + +} + +void mpc_optimise(mpc_parser_t *p) { + mpc_optimise_unretained(p, 1); +} + diff --git a/mpc.h b/mpc.h index d6766f5..826502e 100644 --- a/mpc.h +++ b/mpc.h @@ -16,6 +16,7 @@ #include #include #include +#include /* ** State Type @@ -81,6 +82,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); @@ -219,6 +221,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); @@ -265,6 +270,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); @@ -272,6 +278,30 @@ 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, 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); + +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); + +void mpc_ast_traverse_free(mpc_ast_trav_t **trav); + /* ** Warning: This function currently doesn't test for equality of the `state` member! */ @@ -311,10 +341,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*), diff --git a/package.json b/package.json new file mode 100644 index 0000000..adcb3bf --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "mpc", + "version": "0.8.8", + "repo": "orangeduck/mpc", + "description": "A Parser Combinator library for C", + "keywords": ["parser", "combinator", "library", "c", "mpc"], + "license": "BSD", + "src": ["mpc.c", "mpc.h"] +} diff --git a/tests/core.c b/tests/core.c index abb2ea8..06d7f71 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,93 @@ void test_maths(void) { mpc_cleanup(4, Expr, Factor, Term, Maths); } -void suite_core(void) { - pt_add_test(test_ident, "Test Ident", "Suite Core"); - pt_add_test(test_maths, "Test Maths", "Suite Core"); +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 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 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"); } diff --git a/tests/grammar.c b/tests/grammar.c index 562b0d1..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|>", @@ -91,8 +91,174 @@ 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 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 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"); } diff --git a/tests/ptest.c b/tests/ptest.c index aa8be74..f5ffc8d 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,17 @@ 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) { - (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 +125,30 @@ 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; + 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; } 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 */ @@ -217,15 +242,16 @@ int pt_run(void) { 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..43ca3b5 100644 --- a/tests/ptest.h +++ b/tests/ptest.h @@ -6,17 +6,16 @@ #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)); int pt_run(void); -#endif - +#endif \ No newline at end of file