Merge pull request #3 from pesco/master
add h_in (counterpart to h_not_in)
This commit is contained in:
commit
1f3a75fafe
7 changed files with 166 additions and 7 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -5,3 +5,5 @@ src/test_suite
|
||||||
lib/hush
|
lib/hush
|
||||||
examples/dns
|
examples/dns
|
||||||
TAGS
|
TAGS
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ PARSERS := \
|
||||||
bits \
|
bits \
|
||||||
token \
|
token \
|
||||||
whitespace \
|
whitespace \
|
||||||
|
ignoreseq \
|
||||||
ch \
|
ch \
|
||||||
action \
|
action \
|
||||||
charset \
|
charset \
|
||||||
|
|
@ -21,7 +22,8 @@ PARSERS := \
|
||||||
epsilon \
|
epsilon \
|
||||||
and \
|
and \
|
||||||
not \
|
not \
|
||||||
attr_bool
|
attr_bool \
|
||||||
|
indirect
|
||||||
|
|
||||||
OUTPUTS := bitreader.o \
|
OUTPUTS := bitreader.o \
|
||||||
hammer.o \
|
hammer.o \
|
||||||
|
|
|
||||||
43
src/hammer.c
43
src/hammer.c
|
|
@ -385,6 +385,37 @@ static void test_whitespace(void) {
|
||||||
g_check_parse_failed(whitespace_, "_a", 2);
|
g_check_parse_failed(whitespace_, "_a", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_left(void) {
|
||||||
|
const HParser *left_ = h_left(h_ch('a'), h_ch(' '));
|
||||||
|
|
||||||
|
g_check_parse_ok(left_, "a ", 2, "u0x61");
|
||||||
|
g_check_parse_failed(left_, "a", 1);
|
||||||
|
g_check_parse_failed(left_, " ", 1);
|
||||||
|
g_check_parse_failed(left_, "ab", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_right(void) {
|
||||||
|
const HParser *right_ = h_right(h_ch(' '), h_ch('a'));
|
||||||
|
|
||||||
|
g_check_parse_ok(right_, " a", 2, "u0x61");
|
||||||
|
g_check_parse_failed(right_, "a", 1);
|
||||||
|
g_check_parse_failed(right_, " ", 1);
|
||||||
|
g_check_parse_failed(right_, "ba", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_middle(void) {
|
||||||
|
const HParser *middle_ = h_middle(h_ch(' '), h_ch('a'), h_ch(' '));
|
||||||
|
|
||||||
|
g_check_parse_ok(middle_, " a ", 3, "u0x61");
|
||||||
|
g_check_parse_failed(middle_, "a", 1);
|
||||||
|
g_check_parse_failed(middle_, " ", 1);
|
||||||
|
g_check_parse_failed(middle_, " a", 2);
|
||||||
|
g_check_parse_failed(middle_, "a ", 2);
|
||||||
|
g_check_parse_failed(middle_, " b ", 3);
|
||||||
|
g_check_parse_failed(middle_, "ba ", 3);
|
||||||
|
g_check_parse_failed(middle_, " ab", 3);
|
||||||
|
}
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
const HParsedToken* upcase(const HParseResult *p) {
|
const HParsedToken* upcase(const HParseResult *p) {
|
||||||
|
|
@ -434,6 +465,14 @@ static void test_action(void) {
|
||||||
g_check_parse_failed(action_, "XX", 2);
|
g_check_parse_failed(action_, "XX", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_in(void) {
|
||||||
|
uint8_t options[3] = { 'a', 'b', 'c' };
|
||||||
|
const HParser *in_ = h_in(options, 3);
|
||||||
|
g_check_parse_ok(in_, "b", 1, "u0x62");
|
||||||
|
g_check_parse_failed(in_, "d", 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void test_not_in(void) {
|
static void test_not_in(void) {
|
||||||
uint8_t options[3] = { 'a', 'b', 'c' };
|
uint8_t options[3] = { 'a', 'b', 'c' };
|
||||||
const HParser *not_in_ = h_not_in(options, 3);
|
const HParser *not_in_ = h_not_in(options, 3);
|
||||||
|
|
@ -606,7 +645,11 @@ void register_parser_tests(void) {
|
||||||
g_test_add_func("/core/parser/float32", test_float32);
|
g_test_add_func("/core/parser/float32", test_float32);
|
||||||
#endif
|
#endif
|
||||||
g_test_add_func("/core/parser/whitespace", test_whitespace);
|
g_test_add_func("/core/parser/whitespace", test_whitespace);
|
||||||
|
g_test_add_func("/core/parser/left", test_left);
|
||||||
|
g_test_add_func("/core/parser/right", test_right);
|
||||||
|
g_test_add_func("/core/parser/middle", test_middle);
|
||||||
g_test_add_func("/core/parser/action", test_action);
|
g_test_add_func("/core/parser/action", test_action);
|
||||||
|
g_test_add_func("/core/parser/in", test_in);
|
||||||
g_test_add_func("/core/parser/not_in", test_not_in);
|
g_test_add_func("/core/parser/not_in", test_not_in);
|
||||||
g_test_add_func("/core/parser/end_p", test_end_p);
|
g_test_add_func("/core/parser/end_p", test_end_p);
|
||||||
g_test_add_func("/core/parser/nothing_p", test_nothing_p);
|
g_test_add_func("/core/parser/nothing_p", test_nothing_p);
|
||||||
|
|
|
||||||
33
src/hammer.h
33
src/hammer.h
|
|
@ -222,6 +222,30 @@ const HParser* h_uint8();
|
||||||
*/
|
*/
|
||||||
const HParser* h_whitespace(const HParser* p);
|
const HParser* h_whitespace(const HParser* p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given two parsers, p and q, returns a parser that parses them in
|
||||||
|
* sequence but only returns p's result.
|
||||||
|
*
|
||||||
|
* Result token type: p's result type
|
||||||
|
*/
|
||||||
|
const HParser* h_left(const HParser* p, const HParser* q);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given two parsers, p and q, returns a parser that parses them in
|
||||||
|
* sequence but only returns q's result.
|
||||||
|
*
|
||||||
|
* Result token type: q's result type
|
||||||
|
*/
|
||||||
|
const HParser* h_right(const HParser* p, const HParser* q);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given three parsers, p, x, and q, returns a parser that parses them in
|
||||||
|
* sequence but only returns x's result.
|
||||||
|
*
|
||||||
|
* Result token type: x's result type
|
||||||
|
*/
|
||||||
|
const HParser* h_middle(const HParser* p, const HParser* x, const HParser* q);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given another parser, p, and a function f, returns a parser that
|
* Given another parser, p, and a function f, returns a parser that
|
||||||
* applies p, then applies f to everything in the AST of p's result.
|
* applies p, then applies f to everything in the AST of p's result.
|
||||||
|
|
@ -230,6 +254,13 @@ const HParser* h_whitespace(const HParser* p);
|
||||||
*/
|
*/
|
||||||
const HParser* h_action(const HParser* p, const HAction a);
|
const HParser* h_action(const HParser* p, const HAction a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a single character in the given charset.
|
||||||
|
*
|
||||||
|
* Result token type: TT_UINT
|
||||||
|
*/
|
||||||
|
const HParser* h_in(const uint8_t *charset, size_t length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a single character *NOT* in the given charset.
|
* Parse a single character *NOT* in the given charset.
|
||||||
*
|
*
|
||||||
|
|
@ -441,7 +472,7 @@ HParser *h_indirect();
|
||||||
* Set the inner parser of an indirect. See comments on indirect for
|
* Set the inner parser of an indirect. See comments on indirect for
|
||||||
* details.
|
* details.
|
||||||
*/
|
*/
|
||||||
void h_bind_indirect(HParser* indirect, HParser* inner);
|
void h_bind_indirect(HParser* indirect, const HParser* inner);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free the memory allocated to an HParseResult when it is no longer needed.
|
* Free the memory allocated to an HParseResult when it is no longer needed.
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,24 @@ const HParser* h_ch_range(const uint8_t lower, const uint8_t upper) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const HParser* h_not_in(const uint8_t *options, size_t count) {
|
const HParser* h_in_or_not(const uint8_t *options, size_t count, int val) {
|
||||||
HParser *ret = g_new(HParser, 1);
|
HParser *ret = g_new(HParser, 1);
|
||||||
HCharset cs = new_charset();
|
HCharset cs = new_charset();
|
||||||
for (size_t i = 0; i < 256; i++)
|
for (size_t i = 0; i < 256; i++)
|
||||||
charset_set(cs, i, 1);
|
charset_set(cs, i, 1-val);
|
||||||
for (size_t i = 0; i < count; i++)
|
for (size_t i = 0; i < count; i++)
|
||||||
charset_set(cs, options[i], 0);
|
charset_set(cs, options[i], val);
|
||||||
|
|
||||||
ret->vtable = &charset_vt;
|
ret->vtable = &charset_vt;
|
||||||
ret->env = (void*)cs;
|
ret->env = (void*)cs;
|
||||||
return (const HParser*)ret;
|
return (const HParser*)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HParser* h_in(const uint8_t *options, size_t count) {
|
||||||
|
return h_in_or_not(options, count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HParser* h_not_in(const uint8_t *options, size_t count) {
|
||||||
|
return h_in_or_not(options, count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
73
src/parsers/ignoreseq.c
Normal file
73
src/parsers/ignoreseq.c
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include "parser_internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// general case: parse sequence, pick one result
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const HParser **parsers;
|
||||||
|
size_t count; // how many parsers in 'ps'
|
||||||
|
size_t which; // whose result to return
|
||||||
|
} HIgnoreSeq;
|
||||||
|
|
||||||
|
static HParseResult* parse_ignoreseq(void* env, HParseState *state) {
|
||||||
|
const HIgnoreSeq *seq = (HIgnoreSeq*)env;
|
||||||
|
HParseResult *res = NULL;
|
||||||
|
|
||||||
|
for (size_t i=0; i < seq->count; ++i) {
|
||||||
|
HParseResult *tmp = h_do_parse(seq->parsers[i], state);
|
||||||
|
if (!tmp)
|
||||||
|
return NULL;
|
||||||
|
else if (i == seq->which)
|
||||||
|
res = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const HParserVtable ignoreseq_vt = {
|
||||||
|
.parse = parse_ignoreseq,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// API frontends
|
||||||
|
//
|
||||||
|
|
||||||
|
static const HParser* h_leftright(const HParser* p, const HParser* q, size_t which) {
|
||||||
|
HIgnoreSeq *seq = g_new(HIgnoreSeq, 1);
|
||||||
|
seq->parsers = g_new(const HParser*, 2);
|
||||||
|
seq->parsers[0] = p;
|
||||||
|
seq->parsers[1] = q;
|
||||||
|
seq->count = 2;
|
||||||
|
seq->which = which;
|
||||||
|
|
||||||
|
HParser *ret = g_new(HParser, 1);
|
||||||
|
ret->vtable = &ignoreseq_vt;
|
||||||
|
ret->env = (void*)seq;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HParser* h_left(const HParser* p, const HParser* q) {
|
||||||
|
return h_leftright(p, q, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HParser* h_right(const HParser* p, const HParser* q) {
|
||||||
|
return h_leftright(p, q, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HParser* h_middle(const HParser* p, const HParser* x, const HParser* q) {
|
||||||
|
HIgnoreSeq *seq = g_new(HIgnoreSeq, 1);
|
||||||
|
seq->parsers = g_new(const HParser*, 3);
|
||||||
|
seq->parsers[0] = p;
|
||||||
|
seq->parsers[1] = x;
|
||||||
|
seq->parsers[2] = q;
|
||||||
|
seq->count = 3;
|
||||||
|
seq->which = 1;
|
||||||
|
|
||||||
|
HParser *ret = g_new(HParser, 1);
|
||||||
|
ret->vtable = &ignoreseq_vt;
|
||||||
|
ret->env = (void*)seq;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
@ -7,9 +7,9 @@ static const HParserVtable indirect_vt = {
|
||||||
.parse = parse_indirect,
|
.parse = parse_indirect,
|
||||||
};
|
};
|
||||||
|
|
||||||
void h_bind_indirect(HParser* indirect, HParser* inner) {
|
void h_bind_indirect(HParser* indirect, const HParser* inner) {
|
||||||
assert_message(indirect->vtable == &indirect_vt, "You can only bind an indirect parser");
|
assert_message(indirect->vtable == &indirect_vt, "You can only bind an indirect parser");
|
||||||
indirect->env = inner;
|
indirect->env = (void*)inner;
|
||||||
}
|
}
|
||||||
|
|
||||||
HParser* h_indirect() {
|
HParser* h_indirect() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue