Merge branch 'master' of https://github.com/orangeduck/mpc into nparse

This commit is contained in:
Sean Anderson
2016-06-29 16:23:31 -04:00
16 changed files with 3962 additions and 876 deletions

10
.gitignore vendored
View File

@@ -2,7 +2,9 @@
*.exe
*.dSYM
test
doge
lispy
maths
smallc
examples/doge
examples/lispy
examples/maths
examples/smallc
examples/foobar
examples/tree_traversal

View File

@@ -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).

View File

@@ -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

View File

@@ -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
<tr><td><code>mpc_digits</code></td><td>Matches one or more digit</td></tr>
<tr><td><code>mpc_hexdigits</code></td><td>Matches one or more hexdigit</td></tr>
<tr><td><code>mpc_octdigits</code></td><td>Matches one or more octdigit</td></tr>
<tr><td><code>mpc_lower</code></td><td>Matches and lower case character</td></tr>
<tr><td><code>mpc_lower</code></td><td>Matches any lower case character</td></tr>
<tr><td><code>mpc_upper</code></td><td>Matches any upper case character</td></tr>
<tr><td><code>mpc_alpha</code></td><td>Matches and alphabet character</td></tr>
<tr><td><code>mpc_alpha</code></td><td>Matches any alphabet character</td></tr>
<tr><td><code>mpc_underscore</code></td><td>Matches <code>'_'</code></td></tr>
<tr><td><code>mpc_alphanum</code></td><td>Matches any alphabet character, underscore or digit</td></tr>
<tr><td><code>mpc_int</code></td><td>Matches digits and returns an <code>int*</code></td></tr>
@@ -582,22 +592,22 @@ Useful Parsers
<tr><td><code>mpc_startswith(mpc_parser_t *a);</code></td><td>Matches the start of input followed by <code>a</code></td></tr>
<tr><td><code>mpc_endswith(mpc_parser_t *a, mpc_dtor_t da);</code></td><td>Matches <code>a</code> followed by the end of input</td></tr>
<tr><td><code>mpc_whole(mpc_parser_t *a, mpc_dtor_t da);</code></td><td>Matches the start of input, <code>a</code>, and the end of input</td></tr>
<tr><td><code>mpc_stripl(mpc_parser_t *a);</code></td><td>Matches <code>a</code> striping any whitespace to the left</td></tr>
<tr><td><code>mpc_stripr(mpc_parser_t *a);</code></td><td>Matches <code>a</code> striping any whitespace to the right</td></tr>
<tr><td><code>mpc_strip(mpc_parser_t *a);</code></td><td>Matches <code>a</code> striping any surrounding whitespace</td></tr>
<tr><td><code>mpc_tok(mpc_parser_t *a);</code></td><td>Matches <code>a</code> and strips any trailing whitespace</td></tr>
<tr><td><code>mpc_sym(const char *s);</code></td><td>Matches string <code>s</code> and strips any trailing whitespace</td></tr>
<tr><td><code>mpc_total(mpc_parser_t *a, mpc_dtor_t da);</code></td><td>Matches the whitespace stripped <code>a</code>, enclosed in the start and end of input</td></tr>
<tr><td><code>mpc_stripl(mpc_parser_t *a);</code></td><td>Matches <code>a</code> first consuming any whitespace to the left</td></tr>
<tr><td><code>mpc_stripr(mpc_parser_t *a);</code></td><td>Matches <code>a</code> then consumes any whitespace to the right</td></tr>
<tr><td><code>mpc_strip(mpc_parser_t *a);</code></td><td>Matches <code>a</code> consuming any surrounding whitespace</td></tr>
<tr><td><code>mpc_tok(mpc_parser_t *a);</code></td><td>Matches <code>a</code> and consumes any trailing whitespace</td></tr>
<tr><td><code>mpc_sym(const char *s);</code></td><td>Matches string <code>s</code> and consumes any trailing whitespace</td></tr>
<tr><td><code>mpc_total(mpc_parser_t *a, mpc_dtor_t da);</code></td><td>Matches the whitespace consumed <code>a</code>, enclosed in the start and end of input</td></tr>
<tr><td><code>mpc_between(mpc_parser_t *a, mpc_dtor_t ad, <br /> const char *o, const char *c);</code></td><td> Matches <code>a</code> between strings <code>o</code> and <code>c</code></td></tr>
<tr><td><code>mpc_parens(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between <code>"("</code> and <code>")"</code></td></tr>
<tr><td><code>mpc_braces(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between <code>"<"</code> and <code>">"</code></td></tr>
<tr><td><code>mpc_brackets(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between <code>"{"</code> and <code>"}"</code></td></tr>
<tr><td><code>mpc_squares(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between <code>"["</code> and <code>"]"</code></td></tr>
<tr><td><code>mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad, <br /> const char *o, const char *c);</code></td><td>Matches <code>a</code> between <code>o</code> and <code>c</code>, where <code>o</code> and <code>c</code> have their trailing whitespace striped.</td></tr>
<tr><td><code>mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace stripped <code>"("</code> and <code>")"</code></td></tr>
<tr><td><code>mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace stripped <code>"<"</code> and <code>">"</code></td></tr>
<tr><td><code>mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace stripped <code>"{"</code> and <code>"}"</code></td></tr>
<tr><td><code>mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace stripped <code>"["</code> and <code>"]"</code></td></tr>
<tr><td><code>mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace consumed <code>"("</code> and <code>")"</code></td></tr>
<tr><td><code>mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace consumed <code>"<"</code> and <code>">"</code></td></tr>
<tr><td><code>mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace consumed <code>"{"</code> and <code>"}"</code></td></tr>
<tr><td><code>mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);</code></td><td>Matches <code>a</code> between trailing whitespace consumed <code>"["</code> and <code>"]"</code></td></tr>
</table>
@@ -623,7 +633,9 @@ Apply Functions
<tr><td><code>mpc_val_t *mpcf_unescape_regex(mpc_val_t *x);</code></td><td>Converts a regex <code>x</code> to an unescaped version</td></tr>
<tr><td><code>mpc_val_t *mpcf_unescape_string_raw(mpc_val_t *x);</code></td><td>Converts a raw string <code>x</code> to an unescaped version</td></tr>
<tr><td><code>mpc_val_t *mpcf_unescape_char_raw(mpc_val_t *x);</code></td><td>Converts a raw character <code>x</code> to an unescaped version</td></tr>
<tr><td><code>mpc_val_t *mpcf_strtriml(mpc_val_t *x);</code></td><td>Trims whitespace from the left of string <code>x</code></td></tr>
<tr><td><code>mpc_val_t *mpcf_strtrimr(mpc_val_t *x);</code></td><td>Trims whitespace from the right of string <code>x</code></td></tr>
<tr><td><code>mpc_val_t *mpcf_strtrim(mpc_val_t *x);</code></td><td>Trims whitespace from either side of string <code>x</code></td></tr>
</table>
@@ -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
<test>: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
=================

View File

@@ -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 : <adjective> <noun>; "
" doge : /^/ <phrase>* /$/; ",
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>", stdin, Doge, &r)) {
mpc_ast_print(r.output);
mpc_ast_delete(r.output);

28
examples/foobar.c Normal file
View File

@@ -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 <foo/bar>\n");
exit(0);
}
Foobar = mpc_new("foobar");
mpca_lang(MPCA_LANG_DEFAULT, "foobar : \"foo\" | \"bar\";", Foobar);
if (mpc_parse("<stdin>", 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;
}

View File

@@ -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) {
" | <comment> | <sexpr> | <qexpr> ; "
" lispy : /^/ <expr>* /$/ ; ",
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>", stdin, Lispy, &r)) {
mpc_ast_print(r.output);
mpc_ast_delete(r.output);

2009
examples/so_c.doge Normal file

File diff suppressed because it is too large Load Diff

119
examples/tree_traversal.c Normal file
View File

@@ -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 : '(' <node> ',' /foo/ ',' <node> ')' | <leaf>;"
" leaf : /bar/;"
" input : /^/ <node> /$/;",
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>", 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;
}

2038
mpc.c

File diff suppressed because it is too large Load Diff

35
mpc.h
View File

@@ -16,6 +16,7 @@
#include <string.h>
#include <math.h>
#include <errno.h>
#include <ctype.h>
/*
** 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*),

9
package.json Normal file
View File

@@ -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"]
}

View File

@@ -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");
}

View File

@@ -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 : <adjective> <noun>; "
" doge : /^/ <phrase>* /$/; ",
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 : <line> <number> <quoted_string>;\n"
"parser : /^/ (<linepragma>)* /$/ ;\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 : /^/ (<comment> | <resource>)* /$/ ;\n"
" comment : '#' /[^\\n]*/ ;\n"
"resource : '[' (<rtype> <rname>) ']' <inner_block> ;\n"
" rtype : /[*]*/ ;\n"
" rname : <qstring> ;\n"
"\n"
"inner_block : (<comment> | <statement>)* ;\n"
" statement : <function> '(' (<comment> | <parameter> | <block>)* ')' <seperator> ;\n"
" function : <qstring> ;\n"
" parameter : (<statement> | <literal>) ;\n"
" literal : (<number> | <qstring>) <seperator> ;\n"
" block : '{' <inner_block> '}' ;\n"
" seperator : ',' | \"\" ;\n"
"\n"
"qstring : (<complexstr> | <simplestr>) <qstring>* ;\n"
" simplestr : /[a-zA-Z0-9_!@#$%^&\\*_+\\-\\.=\\/<>]+/ ;\n"
" complexstr : (/\"[^\"]*\"/ | /'[^']*'/) ;\n"
"\n"
"number : (<float> | <int>) ;\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");
}

View File

@@ -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 <windows.h>
#include <windows.h>
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;

View File

@@ -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