Merge github.com:orangeduck/mpc
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ examples/maths
|
||||
examples/smallc
|
||||
examples/foobar
|
||||
examples/tree_traversal
|
||||
build/*
|
69
Makefile
69
Makefile
@@ -1,7 +1,10 @@
|
||||
|
||||
CC = gcc
|
||||
STND=-ansi
|
||||
CFLAGS = $(STND) -pedantic -O3 -g -Wall -Werror -Wextra -Wformat=2 -Wshadow \
|
||||
PROJ = mpc
|
||||
CC ?= gcc
|
||||
STD ?= -ansi
|
||||
DIST = build
|
||||
MKDIR ?= mkdir -p
|
||||
PREFIX ?= /usr/local
|
||||
CFLAGS ?= $(STD) -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
|
||||
@@ -10,15 +13,59 @@ TESTS = $(wildcard tests/*.c)
|
||||
EXAMPLES = $(wildcard examples/*.c)
|
||||
EXAMPLESEXE = $(EXAMPLES:.c=)
|
||||
|
||||
.PHONY: all check clean libs $(DIST)/$(PROJ).pc
|
||||
|
||||
all: $(EXAMPLESEXE) check
|
||||
|
||||
check: $(TESTS) mpc.c
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $^ -lm -o test
|
||||
./test
|
||||
$(DIST):
|
||||
$(MKDIR) $(DIST)/examples
|
||||
|
||||
examples/%: examples/%.c mpc.c
|
||||
$(CC) $(CFLAGS) $^ -lm -o $@
|
||||
check: $(DIST)/test-file $(DIST)/test-static $(DIST)/test-dynamic
|
||||
./$(DIST)/test-file
|
||||
./$(DIST)/test-static
|
||||
LD_LIBRARY_PATH=$(DIST) ./$(DIST)/test-dynamic
|
||||
|
||||
$(DIST)/test-file: $(TESTS) $(PROJ).c $(PROJ).h tests/ptest.h
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $(TESTS) $(PROJ).c -lm -o $(DIST)/test-file
|
||||
|
||||
$(DIST)/test-dynamic: $(TESTS) $(DIST)/lib$(PROJ).so $(PROJ).h tests/ptest.h
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $(TESTS) -lm -L$(DIST) -l$(PROJ) -o $(DIST)/test-dynamic
|
||||
|
||||
$(DIST)/test-static: $(TESTS) $(DIST)/lib$(PROJ).a $(PROJ).h tests/ptest.h
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $(TESTS) -lm -L$(DIST) -l$(PROJ) -static -o $(DIST)/test-static
|
||||
|
||||
examples/%: $(DIST) examples/%.c $(PROJ).c $(PROJ).h
|
||||
$(CC) $(CFLAGS) $(filter-out $(DIST) $(PROJ).h, $^) -lm -o $(DIST)/$@
|
||||
|
||||
$(DIST)/lib$(PROJ).so: $(PROJ).c $(PROJ).h
|
||||
ifneq ($(OS),Windows_NT)
|
||||
$(CC) $(CFLAGS) -fPIC -shared $(PROJ).c -o $(DIST)/lib$(PROJ).so
|
||||
else
|
||||
$(CC) $(CFLAGS) -shared $(PROJ).c -o $(DIST)/lib$(PROJ).so
|
||||
endif
|
||||
|
||||
$(DIST)/lib$(PROJ).a: $(PROJ).c $(PROJ).h
|
||||
$(CC) $(CFLAGS) -c $(PROJ).c -o $(DIST)/$(PROJ).o
|
||||
$(AR) rcs $(DIST)/lib$(PROJ).a $(DIST)/$(PROJ).o
|
||||
|
||||
libs: $(DIST)/lib$(PROJ).so $(DIST)/lib$(PROJ).a
|
||||
|
||||
$(DIST)/$(PROJ).pc: $(DIST) $(PROJ).pc
|
||||
cp $(PROJ).pc $(DIST)/$(PROJ).pc
|
||||
sed -i '1i\prefix=$(PREFIX)/' $(DIST)/$(PROJ).pc
|
||||
|
||||
clean:
|
||||
rm -rf test examples/doge examples/lispy examples/maths examples/smallc \
|
||||
examples/foobar examples/tree_traversal
|
||||
rm -rf -- $(DIST)
|
||||
|
||||
install: all
|
||||
install -d -m644 $(DESTDIR)$(PREFIX)/{include,lib/pkgconfig,share/$(PROJ)}
|
||||
install -m755 -t $(DESTDIR)$(PREFIX)/lib $(DIST)/lib*
|
||||
install -m644 -t $(DESTDIR)$(PREFIX)/share/$(PROJ) $(PROJ).{c,h}
|
||||
install -m644 $(PROJ).h $(DESTDIR)$(PREFIX)/include/$(PROJ).h
|
||||
install -m644 $(DIST)/$(PROJ).pc $(DESTDIR)$(PREFIX)/lib/pkgconfig/$(PROJ).pc
|
||||
|
||||
uninstall:
|
||||
rm -rf -- \
|
||||
$(DESTDIR)$(PREFIX)/include/$(PROJ).h \
|
||||
$(DESTDIR)$(PREFIX)/share/$(PROJ)/$(PROJ).{c,h} \
|
||||
$(DESTDIR)$(PREFIX)/lib/lib$(PROJ).{so,a}
|
||||
|
16
README.md
16
README.md
@@ -1,7 +1,7 @@
|
||||
Micro Parser Combinators
|
||||
========================
|
||||
|
||||
Version 0.8.8
|
||||
Version 0.9.0
|
||||
|
||||
|
||||
About
|
||||
@@ -312,13 +312,13 @@ Returns a parser that applies function `f` (optionality taking extra input `x`)
|
||||
* * *
|
||||
|
||||
```c
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
```
|
||||
|
||||
Returns a parser that applies function `f` (optionally taking extra input `x`) to the result of parser `a`. If `f` returns non-zero, then the parser succeeds and returns the value of `a` (possibly modified by `f`). If `f` returns zero, then the parser fails with message `e`.
|
||||
Returns a parser that applies function `f` (optionally taking extra input `x`) to the result of parser `a`. If `f` returns non-zero, then the parser succeeds and returns the value of `a` (possibly modified by `f`). If `f` returns zero, then the parser fails with message `e`, and the result of `a` is destroyed with the destructor `da`.
|
||||
|
||||
* * *
|
||||
|
||||
@@ -781,6 +781,8 @@ The syntax for this is defined as follows.
|
||||
<tr><td><code>'a' | 'b'</code></td><td>Either <code>'a'</code> is required, or <code>'b'</code> is required.</td></tr>
|
||||
<tr><td><code>'a'*</code></td><td>Zero or more <code>'a'</code> are required.</td></tr>
|
||||
<tr><td><code>'a'+</code></td><td>One or more <code>'a'</code> are required.</td></tr>
|
||||
<tr><td><code>'a'?</code></td><td>Zero or one <code>'a'</code> is required.</td></tr>
|
||||
<tr><td><code>'a'{x}</code></td><td>Exactly <code>x</code> (integer) copies of <code>'a'</code> are required.</td></tr>
|
||||
<tr><td><code><abba></code></td><td>The rule called <code>abba</code> is required.</td></tr>
|
||||
</table>
|
||||
|
||||
@@ -991,5 +993,3 @@ When parsing from a grammar, the abstract syntax tree is tagged with different t
|
||||
If you have a rule in your grammar called `string`, `char` or `regex`, you may encounter some confusion. This is because nodes will be tagged with (for example) `string` _either_ if they are a string primitive, _or_ if they were parsed via your `string` rule. If you are detecting node type using something like `strstr`, in this situation it might break. One solution to this is to always check that `string` is the innermost tag to test for string primitives, or to rename your rule called `string` to something that doesn't conflict.
|
||||
|
||||
Yes it is annoying but its probably not going to change!
|
||||
|
||||
|
||||
|
81
mpc.c
81
mpc.c
@@ -320,6 +320,7 @@ static void mpc_input_mark(mpc_input_t *i) {
|
||||
}
|
||||
|
||||
static void mpc_input_unmark(mpc_input_t *i) {
|
||||
int j;
|
||||
|
||||
if (i->backtrack < 1) { return; }
|
||||
|
||||
@@ -335,6 +336,9 @@ static void mpc_input_unmark(mpc_input_t *i) {
|
||||
}
|
||||
|
||||
if (i->type == MPC_INPUT_PIPE && i->marks_num == 0) {
|
||||
for (j = strlen(i->buffer) - 1; j >= 0; j--)
|
||||
ungetc(i->buffer[j], i->file);
|
||||
|
||||
free(i->buffer);
|
||||
i->buffer = NULL;
|
||||
}
|
||||
@@ -637,7 +641,7 @@ char *mpc_err_string(mpc_err_t *x) {
|
||||
}
|
||||
|
||||
mpc_err_string_cat(buffer, &pos, &max,
|
||||
"%s:%i:%i: error: expected ", x->filename, x->state.row+1, x->state.col+1);
|
||||
"%s:%li:%li: 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]); }
|
||||
@@ -653,7 +657,7 @@ char *mpc_err_string(mpc_err_t *x) {
|
||||
}
|
||||
|
||||
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, mpc_err_char_unescape(x->received));
|
||||
mpc_err_string_cat(buffer, &pos, &max, "\n");
|
||||
|
||||
return realloc(buffer, strlen(buffer) + 1);
|
||||
@@ -671,7 +675,7 @@ static mpc_err_t *mpc_err_new(mpc_input_t *i, const char *expected) {
|
||||
x->expected[0] = mpc_malloc(i, strlen(expected) + 1);
|
||||
strcpy(x->expected[0], expected);
|
||||
x->failure = NULL;
|
||||
x->recieved = mpc_input_peekc(i);
|
||||
x->received = mpc_input_peekc(i);
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -686,7 +690,7 @@ static mpc_err_t *mpc_err_fail(mpc_input_t *i, const char *failure) {
|
||||
x->expected = NULL;
|
||||
x->failure = mpc_malloc(i, strlen(failure) + 1);
|
||||
strcpy(x->failure, failure);
|
||||
x->recieved = ' ';
|
||||
x->received = ' ';
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -700,7 +704,7 @@ static mpc_err_t *mpc_err_file(const char *filename, const char *failure) {
|
||||
x->expected = NULL;
|
||||
x->failure = malloc(strlen(failure) + 1);
|
||||
strcpy(x->failure, failure);
|
||||
x->recieved = ' ';
|
||||
x->received = ' ';
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -777,7 +781,7 @@ static mpc_err_t *mpc_err_or(mpc_input_t *i, mpc_err_t** x, int n) {
|
||||
break;
|
||||
}
|
||||
|
||||
e->recieved = x[j]->recieved;
|
||||
e->received = x[j]->received;
|
||||
|
||||
for (k = 0; k < x[j]->expected_num; k++) {
|
||||
if (!mpc_err_contains_expected(i, e, x[j]->expected[k])) {
|
||||
@@ -923,8 +927,8 @@ typedef struct { int(*f)(char); } mpc_pdata_satisfy_t;
|
||||
typedef struct { char *x; } mpc_pdata_string_t;
|
||||
typedef struct { mpc_parser_t *x; mpc_apply_t f; } mpc_pdata_apply_t;
|
||||
typedef struct { mpc_parser_t *x; mpc_apply_to_t f; void *d; } mpc_pdata_apply_to_t;
|
||||
typedef struct { mpc_parser_t *x; mpc_check_t f; char *e; } mpc_pdata_check_t;
|
||||
typedef struct { mpc_parser_t *x; mpc_check_with_t f; void *d; char *e; } mpc_pdata_check_with_t;
|
||||
typedef struct { mpc_parser_t *x; mpc_dtor_t dx; mpc_check_t f; char *e; } mpc_pdata_check_t;
|
||||
typedef struct { mpc_parser_t *x; mpc_dtor_t dx; mpc_check_with_t f; void *d; char *e; } mpc_pdata_check_with_t;
|
||||
typedef struct { mpc_parser_t *x; } mpc_pdata_predict_t;
|
||||
typedef struct { mpc_parser_t *x; mpc_dtor_t dx; mpc_ctor_t lf; } mpc_pdata_not_t;
|
||||
typedef struct { int n; mpc_fold_t f; mpc_parser_t *x; mpc_dtor_t dx; } mpc_pdata_repeat_t;
|
||||
@@ -1038,13 +1042,20 @@ enum {
|
||||
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) {
|
||||
#define MPC_MAX_RECURSION_DEPTH 1000
|
||||
|
||||
static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_err_t **e, int depth) {
|
||||
|
||||
int j = 0, k = 0;
|
||||
mpc_result_t results_stk[MPC_PARSE_STACK_MIN];
|
||||
mpc_result_t *results;
|
||||
int results_slots = MPC_PARSE_STACK_MIN;
|
||||
|
||||
if (depth == MPC_MAX_RECURSION_DEPTH)
|
||||
{
|
||||
MPC_FAILURE(mpc_err_fail(i, "Maximum recursion depth exceeded!"));
|
||||
}
|
||||
|
||||
switch (p->type) {
|
||||
|
||||
/* Basic Parsers */
|
||||
@@ -1072,24 +1083,25 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
/* Application Parsers */
|
||||
|
||||
case MPC_TYPE_APPLY:
|
||||
if (mpc_parse_run(i, p->data.apply.x, r, e)) {
|
||||
if (mpc_parse_run(i, p->data.apply.x, r, e, depth+1)) {
|
||||
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)) {
|
||||
if (mpc_parse_run(i, p->data.apply_to.x, r, e, depth+1)) {
|
||||
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_CHECK:
|
||||
if (mpc_parse_run(i, p->data.check.x, r, e)) {
|
||||
if (mpc_parse_run(i, p->data.check.x, r, e, depth+1)) {
|
||||
if (p->data.check.f(&r->output)) {
|
||||
MPC_SUCCESS(r->output);
|
||||
} else {
|
||||
mpc_parse_dtor(i, p->data.check.dx, r->output);
|
||||
MPC_FAILURE(mpc_err_fail(i, p->data.check.e));
|
||||
}
|
||||
} else {
|
||||
@@ -1097,10 +1109,11 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
}
|
||||
|
||||
case MPC_TYPE_CHECK_WITH:
|
||||
if (mpc_parse_run(i, p->data.check_with.x, r, e)) {
|
||||
if (mpc_parse_run(i, p->data.check_with.x, r, e, depth+1)) {
|
||||
if (p->data.check_with.f(&r->output, p->data.check_with.d)) {
|
||||
MPC_SUCCESS(r->output);
|
||||
} else {
|
||||
mpc_parse_dtor(i, p->data.check.dx, r->output);
|
||||
MPC_FAILURE(mpc_err_fail(i, p->data.check_with.e));
|
||||
}
|
||||
} else {
|
||||
@@ -1109,7 +1122,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
|
||||
case MPC_TYPE_EXPECT:
|
||||
mpc_input_suppress_enable(i);
|
||||
if (mpc_parse_run(i, p->data.expect.x, r, e)) {
|
||||
if (mpc_parse_run(i, p->data.expect.x, r, e, depth+1)) {
|
||||
mpc_input_suppress_disable(i);
|
||||
MPC_SUCCESS(r->output);
|
||||
} else {
|
||||
@@ -1119,7 +1132,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
|
||||
case MPC_TYPE_PREDICT:
|
||||
mpc_input_backtrack_disable(i);
|
||||
if (mpc_parse_run(i, p->data.predict.x, r, e)) {
|
||||
if (mpc_parse_run(i, p->data.predict.x, r, e, depth+1)) {
|
||||
mpc_input_backtrack_enable(i);
|
||||
MPC_SUCCESS(r->output);
|
||||
} else {
|
||||
@@ -1134,7 +1147,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
case MPC_TYPE_NOT:
|
||||
mpc_input_mark(i);
|
||||
mpc_input_suppress_enable(i);
|
||||
if (mpc_parse_run(i, p->data.not.x, r, e)) {
|
||||
if (mpc_parse_run(i, p->data.not.x, r, e, depth+1)) {
|
||||
mpc_input_rewind(i);
|
||||
mpc_input_suppress_disable(i);
|
||||
mpc_parse_dtor(i, p->data.not.dx, r->output);
|
||||
@@ -1146,7 +1159,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
}
|
||||
|
||||
case MPC_TYPE_MAYBE:
|
||||
if (mpc_parse_run(i, p->data.not.x, r, e)) {
|
||||
if (mpc_parse_run(i, p->data.not.x, r, e, depth+1)) {
|
||||
MPC_SUCCESS(r->output);
|
||||
} else {
|
||||
*e = mpc_err_merge(i, *e, r->error);
|
||||
@@ -1159,7 +1172,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
|
||||
results = results_stk;
|
||||
|
||||
while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) {
|
||||
while (mpc_parse_run(i, p->data.repeat.x, &results[j], e, depth+1)) {
|
||||
j++;
|
||||
if (j == MPC_PARSE_STACK_MIN) {
|
||||
results_slots = j + j / 2;
|
||||
@@ -1181,7 +1194,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
|
||||
results = results_stk;
|
||||
|
||||
while (mpc_parse_run(i, p->data.repeat.x, &results[j], e)) {
|
||||
while (mpc_parse_run(i, p->data.repeat.x, &results[j], e, depth+1)) {
|
||||
j++;
|
||||
if (j == MPC_PARSE_STACK_MIN) {
|
||||
results_slots = j + j / 2;
|
||||
@@ -1212,7 +1225,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
? 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)) {
|
||||
while (mpc_parse_run(i, p->data.repeat.x, &results[j], e, depth+1)) {
|
||||
j++;
|
||||
if (j == p->data.repeat.n) { break; }
|
||||
}
|
||||
@@ -1241,7 +1254,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
: results_stk;
|
||||
|
||||
for (j = 0; j < p->data.or.n; j++) {
|
||||
if (mpc_parse_run(i, p->data.or.xs[j], &results[j], e)) {
|
||||
if (mpc_parse_run(i, p->data.or.xs[j], &results[j], e, depth+1)) {
|
||||
MPC_SUCCESS(results[j].output;
|
||||
if (p->data.or.n > MPC_PARSE_STACK_MIN) { mpc_free(i, results); });
|
||||
} else {
|
||||
@@ -1262,7 +1275,7 @@ static int mpc_parse_run(mpc_input_t *i, mpc_parser_t *p, mpc_result_t *r, mpc_e
|
||||
|
||||
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)) {
|
||||
if (!mpc_parse_run(i, p->data.and.xs[j], &results[j], e, depth+1)) {
|
||||
mpc_input_rewind(i);
|
||||
for (k = 0; k < j; k++) {
|
||||
mpc_parse_dtor(i, p->data.and.dxs[k], results[k].output);
|
||||
@@ -1295,7 +1308,7 @@ 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);
|
||||
x = mpc_parse_run(i, p, r, &e, 0);
|
||||
if (x) {
|
||||
mpc_err_delete_internal(i, e);
|
||||
r->output = mpc_export(i, r->output);
|
||||
@@ -1799,20 +1812,22 @@ mpc_parser_t *mpc_apply_to(mpc_parser_t *a, mpc_apply_to_t f, void *x) {
|
||||
return p;
|
||||
}
|
||||
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_check_t f, const char *e) {
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *e) {
|
||||
mpc_parser_t *p = mpc_undefined();
|
||||
p->type = MPC_TYPE_CHECK;
|
||||
p->data.check.x = a;
|
||||
p->data.check.dx = da;
|
||||
p->data.check.f = f;
|
||||
p->data.check.e = malloc(strlen(e) + 1);
|
||||
strcpy(p->data.check.e, e);
|
||||
return p;
|
||||
}
|
||||
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *e) {
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *e) {
|
||||
mpc_parser_t *p = mpc_undefined();
|
||||
p->type = MPC_TYPE_CHECK_WITH;
|
||||
p->data.check_with.x = a;
|
||||
p->data.check_with.dx = da;
|
||||
p->data.check_with.f = f;
|
||||
p->data.check_with.d = x;
|
||||
p->data.check_with.e = malloc(strlen(e) + 1);
|
||||
@@ -1820,7 +1835,7 @@ mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_check_with_t f, void *x, const
|
||||
return p;
|
||||
}
|
||||
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_check_t f, const char *fmt, ...) {
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *fmt, ...) {
|
||||
va_list va;
|
||||
char *buffer;
|
||||
mpc_parser_t *p;
|
||||
@@ -1830,13 +1845,13 @@ mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_check_t f, const char *fmt, ...) {
|
||||
vsprintf(buffer, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
p = mpc_check (a, f, buffer);
|
||||
free (buffer);
|
||||
p = mpc_check(a, da, f, buffer);
|
||||
free(buffer);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *fmt, ...) {
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *fmt, ...) {
|
||||
va_list va;
|
||||
char *buffer;
|
||||
mpc_parser_t *p;
|
||||
@@ -1846,8 +1861,8 @@ mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_check_with_t f, void *x, cons
|
||||
vsprintf(buffer, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
p = mpc_check_with (a, f, x, buffer);
|
||||
free (buffer);
|
||||
p = mpc_check_with(a, da, f, x, buffer);
|
||||
free(buffer);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -2446,7 +2461,7 @@ mpc_val_t *mpcf_float(mpc_val_t *x) {
|
||||
|
||||
mpc_val_t *mpcf_strtriml(mpc_val_t *x) {
|
||||
char *s = x;
|
||||
while (isspace(*s)) {
|
||||
while (isspace((unsigned char)*s)) {
|
||||
memmove(s, s+1, strlen(s));
|
||||
}
|
||||
return s;
|
||||
@@ -2455,7 +2470,7 @@ mpc_val_t *mpcf_strtriml(mpc_val_t *x) {
|
||||
mpc_val_t *mpcf_strtrimr(mpc_val_t *x) {
|
||||
char *s = x;
|
||||
size_t l = strlen(s);
|
||||
while (isspace(s[l-1])) {
|
||||
while (l > 0 && isspace((unsigned char)s[l-1])) {
|
||||
s[l-1] = '\0'; l--;
|
||||
}
|
||||
return s;
|
||||
|
11
mpc.h
11
mpc.h
@@ -43,7 +43,7 @@ typedef struct {
|
||||
char *filename;
|
||||
char *failure;
|
||||
char **expected;
|
||||
char recieved;
|
||||
char received;
|
||||
} mpc_err_t;
|
||||
|
||||
void mpc_err_delete(mpc_err_t *e);
|
||||
@@ -129,10 +129,10 @@ mpc_parser_t *mpc_expect(mpc_parser_t *a, const char *e);
|
||||
mpc_parser_t *mpc_expectf(mpc_parser_t *a, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_apply(mpc_parser_t *a, mpc_apply_t f);
|
||||
mpc_parser_t *mpc_apply_to(mpc_parser_t *a, mpc_apply_to_t f, void *x);
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
|
||||
mpc_parser_t *mpc_not(mpc_parser_t *a, mpc_dtor_t da);
|
||||
mpc_parser_t *mpc_not_lift(mpc_parser_t *a, mpc_dtor_t da, mpc_ctor_t lf);
|
||||
@@ -258,6 +258,7 @@ mpc_val_t *mpcf_snd_free(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_trd_free(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_all_free(int n, mpc_val_t** xs);
|
||||
|
||||
mpc_val_t *mpcf_freefold(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_strfold(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_maths(int n, mpc_val_t** xs);
|
||||
|
||||
|
8
mpc.pc
Normal file
8
mpc.pc
Normal file
@@ -0,0 +1,8 @@
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: mpc
|
||||
Description: Library for creating parser combinators
|
||||
Version: 0.9.0
|
||||
Libs: -L${libdir} -lmpc
|
||||
Cflags: -I${includedir}
|
@@ -12,7 +12,7 @@ static int check_is(mpc_val_t** x, void* t) {
|
||||
void test_check(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_check(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is_a, "Expected 'a'");
|
||||
mpc_parser_t* p = mpc_check(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is_a, "Expected 'a'");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
@@ -30,7 +30,7 @@ void test_check(void) {
|
||||
void test_check_with(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_check_with(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is, (void*)"a", "Expected 'a'");
|
||||
mpc_parser_t* p = mpc_check_with(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is, (void*)"a", "Expected 'a'");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
@@ -48,7 +48,7 @@ void test_check_with(void) {
|
||||
void test_checkf(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_checkf(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is_a, "Expected '%s'", "a");
|
||||
mpc_parser_t* p = mpc_checkf(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is_a, "Expected '%s'", "a");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
@@ -66,7 +66,7 @@ void test_checkf(void) {
|
||||
void test_check_withf(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_check_withf(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is, (void*)"a", "Expected '%s'", "a");
|
||||
mpc_parser_t* p = mpc_check_withf(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is, (void*)"a", "Expected '%s'", "a");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
|
Reference in New Issue
Block a user