From 342e39eb61bf583d582938ceaad3949c9b0665f5 Mon Sep 17 00:00:00 2001
From: "Sven M. Hallberg" <pesco@khjk.org>
Date: Tue, 15 Jan 2013 20:02:53 +0100
Subject: [PATCH] add helpers for easier token construction and access to
 sequence elements

---
 examples/dns.c | 154 +++++++++++++++++++++++++++++++------------------
 1 file changed, 97 insertions(+), 57 deletions(-)

diff --git a/examples/dns.c b/examples/dns.c
index 6db8bf82..01442c80 100644
--- a/examples/dns.c
+++ b/examples/dns.c
@@ -11,9 +11,79 @@
 #define false 0
 #define true 1
 
+
+///
+// API Additions
+///
+
 #define H_RULE(rule, def) const HParser *rule = def
 #define H_ARULE(rule, def) const HParser *rule = h_action(def, act_ ## rule)
 
+// 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);
+}
+
+HParsedToken *h_make_token(HArena *arena, HTokenType type, void *value) {
+  HParsedToken *ret = h_arena_malloc(arena, sizeof(HParsedToken));
+  ret->token_type = type;
+  ret->user = value;
+  return ret;
+}
+
+#define H_MAKE(TYP) \
+  ((TYP ## _t *) h_arena_malloc(p->arena, sizeof(TYP ## _t)))
+
+#define H_MAKE_TOKEN(TYP, VAL) \
+  h_make_token(p->arena, TT_ ## TYP, VAL)
+
+HParsedToken *h_carray_index(const HCountedArray *a, size_t i) {
+  assert(i < a->used);
+  return a->elements[i];
+}
+
+HParsedToken *h_seq_index(const HParsedToken *p, size_t i) {
+  assert(p->token_type == TT_SEQUENCE);
+  return h_carray_index(p->seq, i);
+}
+
+void *h_seq_index_user(HTokenType type, const HParsedToken *p, size_t i) {
+  HParsedToken *elem = h_seq_index(p, i);
+  assert(elem->token_type == (HTokenType)type);
+  return elem->user;
+}
+
+#define H_SEQ_INDEX(TYP, SEQ, IDX) \
+  ((TYP ## _t *) h_seq_index_user(TT_ ## TYP, SEQ, IDX))
+
+#define H_FIELD(TYP, IDX) \
+  H_SEQ_INDEX(TYP, p->ast, IDX)
+
 
 bool is_zero(HParseResult *p) {
   if (TT_UINT != p->ast->token_type)
@@ -21,6 +91,11 @@ bool is_zero(HParseResult *p) {
   return (0 == p->ast->uint);
 }
 
+
+///
+// Semantic Actions
+///
+
 /**
  * Every DNS message should have QDCOUNT entries in the question
  * section, and ANCOUNT+NSCOUNT+ARCOUNT resource records.
@@ -268,10 +343,6 @@ void set_rr(struct dns_rr rr, HCountedArray *rdata) {
 }
 
 const HParsedToken* act_header(const HParseResult *p) {
-  HParsedToken *ret = h_arena_malloc(p->arena, sizeof(HParsedToken));
-  ret->token_type = TT_dns_header;
-  ret->user = h_arena_malloc(p->arena, sizeof(dns_header_t));
-
   HParsedToken **fields = p->ast->seq->elements;
   dns_header_t header_ = {
     .id     = fields[0]->uint,
@@ -287,16 +358,15 @@ const HParsedToken* act_header(const HParseResult *p) {
     .authority_count  = fields[10]->uint,
     .additional_count = fields[11]->uint
   };
-  *(dns_header_t *)ret->user = header_;
 
-  return ret;
+  dns_header_t *header = H_MAKE(dns_header);
+  *header = header_;
+
+  return H_MAKE_TOKEN(dns_header, header);
 }
 
 const HParsedToken* act_label(const HParseResult *p) {
-  HParsedToken *ret = h_arena_malloc(p->arena, sizeof(HParsedToken));
-  ret->token_type = TT_dns_label;
-  ret->user = h_arena_malloc(p->arena, sizeof(dns_label_t));
-  dns_label_t *r = (dns_label_t *)ret->user;
+  dns_label_t *r = H_MAKE(dns_label);
 
   r->len = p->ast->seq->used;
   r->label = h_arena_malloc(p->arena, r->len + 1);
@@ -304,41 +374,31 @@ const HParsedToken* act_label(const HParseResult *p) {
     r->label[i] = p->ast->seq->elements[i]->uint;
   r->label[r->len] = 0;
 
-  return ret;
+  return H_MAKE_TOKEN(dns_label, r);
 }
 
 const HParsedToken* act_question(const HParseResult *p) {
-  HParsedToken *ret = h_arena_malloc(p->arena, sizeof(HParsedToken));
-  ret->token_type = TT_dns_question;
-  ret->user = h_arena_malloc(p->arena, sizeof(dns_question_t));
-
-  dns_question_t *q = (dns_question_t *)ret->user;
+  dns_question_t *q = H_MAKE(dns_question);
   HParsedToken **fields = p->ast->seq->elements;
 
   // QNAME is a sequence of labels. Pack them into an array.
   q->qname.qlen   = fields[0]->seq->used;
   q->qname.labels = h_arena_malloc(p->arena, sizeof(dns_label_t)*q->qname.qlen);
   for(size_t i=0; i<fields[0]->seq->used; i++) {
-    assert(fields[0]->seq->elements[i]->token_type == (HTokenType)TT_dns_label);
-    q->qname.labels[i] = *(dns_label_t *)fields[0]->seq->elements[i]->user;
+    q->qname.labels[i] = *H_SEQ_INDEX(dns_label, fields[0], i);
   }
 
   q->qtype  = fields[1]->uint;
   q->qclass = fields[2]->uint;
 
-  return ret;
+  return H_MAKE_TOKEN(dns_question, q);
 }
 
 const HParsedToken* act_message(const HParseResult *p) {
   h_pprint(stdout, p->ast, 0, 2);
+  dns_message_t *msg = H_MAKE(dns_message);
 
-  HParsedToken *ret = h_arena_malloc(p->arena, sizeof(HParsedToken));
-  ret->token_type = TT_dns_message;
-  ret->user = h_arena_malloc(p->arena, sizeof(dns_message_t));
-  dns_message_t *msg = ret->user;
-
-  assert(p->ast->seq->elements[0]->token_type == (HTokenType)TT_dns_header);
-  dns_header_t *header = (dns_header_t *)p->ast->seq->elements[0]->user;
+  dns_header_t *header = H_FIELD(dns_header, 0);
   msg->header = *header;
 
   HParsedToken *qs = p->ast->seq->elements[1];
@@ -387,42 +447,17 @@ const HParsedToken* act_message(const HParseResult *p) {
   }
   msg->additional = additional;
 
-  return ret;
-}
-
-// 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);
+  return H_MAKE_TOKEN(dns_message, msg);
 }
 
 #define act_hdzero act_ignore
 #define act_qname  act_index0
 
+
+///
+// Parser / Grammar
+///
+
 const HParser* init_parser() {
   static const HParser *ret = NULL;
   if (ret)
@@ -476,6 +511,11 @@ const HParser* init_parser() {
   return ret;
 }
 
+
+///
+// Program Logic for a Dummy DNS Server
+///
+
 int start_listening() {
   // return: fd
   int sock;
-- 
GitLab