[augeas-devel] [PATCH 2/6] Build AST while visiting the parse

Francis Giraldeau francis.giraldeau at gmail.com
Sun Aug 12 21:37:18 UTC 2012


The AST records the structure of the parse according to the lens tree. The
indices of the text matched is recorded for later use.
---
 src/get.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)

diff --git a/src/get.c b/src/get.c
index 734abf6..05663a4 100644
--- a/src/get.c
+++ b/src/get.c
@@ -90,6 +90,17 @@ struct frame {
 /* Used by recursive lenses in get_rec and parse_rec */
 enum mode_t { M_GET, M_PARSE };
 
+/* Abstract Syntax Tree for recursive parse */
+struct ast {
+    struct ast         *parent;
+    struct ast        **children;
+    uint                nchildren;
+    uint                capacity;
+    struct lens        *lens;
+    uint                start;
+    uint                end;
+};
+
 struct rec_state {
     enum mode_t          mode;
     struct state        *state;
@@ -98,6 +109,7 @@ struct rec_state {
     struct frame        *frames;
     size_t               start;
     uint                 lvl;  /* Debug only */
+    struct ast          *ast;
 };
 
 #define REG_START(state) ((state)->regs->start[(state)->nreg])
@@ -109,6 +121,102 @@ struct rec_state {
 #define REG_MATCHED(state) (REG_VALID(state)                            \
                             && (state)->regs->start[(state)->nreg] >= 0)
 
+/*
+ * AST utils
+ */
+static struct ast *make_ast(struct lens *lens) {
+    struct ast *ast = NULL;
+
+    if (ALLOC(ast) < 0)
+        return NULL;
+    ast->lens = lens;
+    ast->capacity = 4;
+    if (ALLOC_N(ast->children, ast->capacity) < 0) {
+        FREE(ast);
+        return NULL;
+    }
+    return ast;
+}
+
+/* recursively free the node and all it's descendants */
+static void free_ast(struct ast *ast) {
+    int i;
+    if (ast == NULL)
+        return;
+    for (i = 0; i < ast->nchildren; i++) {
+        free_ast(ast->children[i]);
+    }
+    if (ast->children != NULL)
+        FREE(ast->children);
+    FREE(ast);
+}
+
+static struct ast *ast_root(struct ast *ast) {
+    struct ast *root = ast;
+    while(root != NULL && root->parent != NULL)
+        root = root->parent;
+    return root;
+}
+
+/* append a child to the parent ast */
+ATTRIBUTE_RETURN_CHECK
+static int ast_add_child(struct ast *parent, struct ast *child) {
+    if (parent == NULL)
+        return 0;
+    if (parent->nchildren >= parent->capacity) {
+        int ret = REALLOC_N(parent->children, parent->capacity * 2);
+        if (ret < 0)
+            return -1;
+        parent->capacity = parent->capacity * 2;
+    }
+    parent->children[parent->nchildren++] = child;
+    child->parent = parent;
+    return 0;
+}
+
+static void ast_set(struct ast *ast, uint start, uint end) {
+    if (ast == NULL)
+        return;
+    ast->start = start;
+    ast->end = end;
+}
+
+static struct ast *ast_append(struct rec_state *rec_state, struct lens *lens,
+                           uint start, uint end) {
+    int ret;
+    struct ast *child;
+
+    child = make_ast(lens);
+    ERR_NOMEM(child == NULL, rec_state->state->info);
+    ast_set(child, start, end);
+    ret = ast_add_child(rec_state->ast, child);
+    ERR_NOMEM(ret < 0, rec_state->state->info)
+    return child;
+ error:
+    free_ast(child);
+    return NULL;
+}
+
+/* pop the ast from one level if parent is not null */
+static void ast_pop(struct rec_state *rec_state) {
+    if (rec_state->ast != NULL && rec_state->ast->parent != NULL)
+        rec_state->ast = rec_state->ast->parent;
+}
+
+static void print_ast(struct ast *ast, int lvl) {
+    int i;
+    char *lns;
+    if (ast == NULL)
+        return;
+    for (i = 0; i < lvl; i++) fputs(" ", stdout);
+    lns = format_lens(ast->lens);
+    printf("%d..%d %s\n", ast->start, ast->end, lns);
+    free(lns);
+    for (i = 0; i < ast->nchildren; i++) {
+        print_ast(ast->children[i], lvl + 1);
+    }
+}
+
 static void get_error(struct state *state, struct lens *lens,
                       const char *format, ...)
     ATTRIBUTE_FORMAT(printf, 3, 4);
@@ -871,6 +979,7 @@ static void visit_terminal(struct lens *lens, size_t start, size_t end,
         get_terminal(top, lens, state);
     else
         parse_terminal(top, lens, state);
+    ast_append(rec_state, lens, start, end);
     free_regs(state);
     state->regs = old_regs;
     state->nreg = old_nreg;
@@ -882,6 +991,7 @@ static void visit_enter(struct lens *lens,
                         void *data) {
     struct rec_state *rec_state = data;
     struct state *state = rec_state->state;
+    struct ast *child;
 
     if (state->error != NULL)
         return;
@@ -904,6 +1014,9 @@ static void visit_enter(struct lens *lens,
             ERR_NOMEM(state->span == NULL, state->info);
         }
     }
+    child = ast_append(rec_state, lens, start, end);
+    if (child != NULL)
+        rec_state->ast = child;
  error:
     return;
 }
@@ -1082,6 +1195,7 @@ static void visit_exit(struct lens *lens,
     } else {
         top_frame(rec_state)->lens = lens;
     }
+    ast_pop(rec_state);
  error:
     return;
 }
@@ -1151,12 +1265,16 @@ static struct frame *rec_process(enum mode_t mode, struct lens *lens,
     }
 
  done:
+    if (debugging("cf.get.ast"))
+        print_ast(rec_state.ast, 0);
     state->regs = old_regs;
     state->nreg = old_nreg;
     jmt_free_parse(visitor.parse);
+    free_ast(rec_state.ast);
     return rec_state.frames;
  error:
 
+    rec_state.ast = ast_root(rec_state.ast);
     for(i = 0; i < rec_state.fused; i++) {
         f = nth_frame(&rec_state, i);
         FREE(f->key);
-- 
1.7.9.5




More information about the augeas-devel mailing list