diff --git a/examples/Makefile b/examples/Makefile index 6a054cad515f9e697fb5d1a954824e8a00cfe259..a3be0ce087ff8c429adabd17e775afd04eb65206 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,7 +2,9 @@ OUTPUTS := dns.o \ dns \ base64.o \ - base64 + base64 \ + base64_sem1.o \ + base64_sem1 TOPLEVEL := ../ @@ -12,7 +14,7 @@ LDFLAGS += $(pkg-config --libs glib-2.0) -all: dns base64 +all: dns base64 base64_sem1 dns: LDFLAGS:=-L../src -lhammer $(LDFLAGS) dns: dns.o rr.o dns_common.o @@ -24,8 +26,8 @@ rr.o: ../src/hammer.h rr.h dns_common.h dns_common.o: ../src/hammer.h dns_common.h -base64: LDFLAGS:=-L../src -lhammer $(LDFLAGS) -base64: base64.o +base64%: LDFLAGS:=-L../src -lhammer $(LDFLAGS) +base64%: base64%.o $(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS) -base64.o: ../src/hammer.h +base64%.o: ../src/hammer.h diff --git a/examples/base64_sem1.c b/examples/base64_sem1.c new file mode 100644 index 0000000000000000000000000000000000000000..83efc644056f70c9370ddc1045fefc11b74a2b50 --- /dev/null +++ b/examples/base64_sem1.c @@ -0,0 +1,142 @@ +#include "../src/hammer.h" +#include <assert.h> + + +#define H_RULE(rule, def) const HParser *rule = def +#define H_ARULE(rule, def) const HParser *rule = h_action(def, act_ ## rule) + + +/// +// Semantic action helpers. +// These might be candidates for inclusion in the library. +/// + +// The action equivalent of h_ignore. +const HParsedToken *act_ignore(const HParseResult *p) +{ + return NULL; +} + +// Helper to build HAction's that pick one index out of a sequence. +const HParsedToken *act_index(int i, const HParseResult *p) +{ + if(!p) return NULL; + + const HParsedToken *tok = p->ast; + + if(!tok || tok->token_type != TT_SEQUENCE) + return NULL; + + const HCountedArray *seq = tok->seq; + size_t n = seq->used; + + if(i<0 || (size_t)i>=n) + return NULL; + else + return tok->seq->elements[i]; +} + +const HParsedToken *act_index0(const HParseResult *p) +{ + return act_index(0, p); +} + + +/// +// Semantic actions for the grammar below, each corresponds to an "ARULE". +// They must be named act_<rulename>. +/// + +const HParsedToken *act_bsfdig(const HParseResult *p) +{ + HParsedToken *res = h_arena_malloc(p->arena, sizeof(HParsedToken)); + + assert(p->ast->token_type == TT_UINT); + uint8_t c = p->ast->uint; + + res->token_type = TT_UINT; + if(c >= 0x40 && c <= 0x5A) // A-Z + res->uint = c - 0x41; + else if(c >= 0x60 && c <= 0x7A) // a-z + res->uint = c - 0x61 + 26; + else if(c >= 0x30 && c <= 0x39) // 0-9 + res->uint = c - 0x30 + 52; + else if(c == '+') + res->uint = 62; + else if(c == '/') + res->uint = 63; + + return res; +} + +#define act_bsfdig_4bit act_bsfdig +#define act_bsfdig_2bit act_bsfdig + +#define act_equals act_ignore +#define act_ws act_ignore + +#define act_document act_index0 + + +/// +// Set up the parser with the grammar to be recognized. +/// + +const HParser *init_parser(void) +{ + // CORE + H_RULE (digit, h_ch_range(0x30, 0x39)); + H_RULE (alpha, h_choice(h_ch_range(0x41, 0x5a), h_ch_range(0x61, 0x7a), NULL)); + H_RULE (space, h_in((uint8_t *)" \t\n\r\f\v", 6)); + + // AUX. + H_RULE (plus, h_ch('+')); + H_RULE (slash, h_ch('/')); + H_ARULE(equals, h_ch('=')); + + H_ARULE(bsfdig, h_choice(alpha, digit, plus, slash, NULL)); + H_ARULE(bsfdig_4bit, h_in((uint8_t *)"AEIMQUYcgkosw048", 16)); + H_ARULE(bsfdig_2bit, h_in((uint8_t *)"AQgw", 4)); + H_RULE (base64_3, h_repeat_n(bsfdig, 4)); + H_RULE (base64_2, h_sequence(bsfdig, bsfdig, bsfdig_4bit, equals, NULL)); + H_RULE (base64_1, h_sequence(bsfdig, bsfdig_2bit, equals, equals, NULL)); + H_RULE (base64, h_sequence(h_many(base64_3), + h_optional(h_choice(base64_2, + base64_1, NULL)), + NULL)); + + H_ARULE(ws, h_many(space)); + H_ARULE(document, h_sequence(ws, base64, ws, h_end_p(), NULL)); + + return document; +} + + +/// +// Main routine: print input, parse, print result, return success/failure. +/// + +#include <stdio.h> + +int main(int argc, char **argv) +{ + uint8_t input[102400]; + size_t inputsize; + const HParser *parser; + const HParseResult *result; + + parser = init_parser(); + + inputsize = fread(input, 1, sizeof(input), stdin); + fprintf(stderr, "inputsize=%lu\ninput=", inputsize); + fwrite(input, 1, inputsize, stderr); + result = h_parse(parser, input, inputsize); + + if(result) { + fprintf(stderr, "parsed=%lld bytes\n", result->bit_length/8); + h_pprint(stdout, result->ast, 0, 0); + return 0; + } else { + return 1; + } +}