xref: /dragonfly/contrib/tre/lib/tre-ast.c (revision d5f8dde1e2bae450329b3ee8c25ef109b5713f07)
1 /*
2   tre-ast.c - Abstract syntax tree (AST) routines
3 
4   This software is released under a BSD-style license.
5   See the file LICENSE for details and copyright.
6 
7 */
8 
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif /* HAVE_CONFIG_H */
12 #include <assert.h>
13 
14 #include "tre-ast.h"
15 #include "tre-mem.h"
16 
17 tre_ast_node_t *
tre_ast_new_node(tre_mem_t mem,tre_ast_type_t type,size_t size)18 tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size)
19 {
20   tre_ast_node_t *node;
21 
22   node = tre_mem_calloc(mem, sizeof(*node));
23   if (!node)
24     return NULL;
25   node->obj = tre_mem_calloc(mem, size);
26   if (!node->obj)
27     return NULL;
28   node->type = type;
29   node->nullable = -1;
30   node->submatch_id = -1;
31 
32   return node;
33 }
34 
35 tre_ast_node_t *
tre_ast_new_literal(tre_mem_t mem,int code_min,int code_max,int position)36 tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position)
37 {
38   tre_ast_node_t *node;
39   tre_literal_t *lit;
40 
41   node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t));
42   if (!node)
43     return NULL;
44   lit = node->obj;
45   lit->code_min = code_min;
46   lit->code_max = code_max;
47   lit->position = position;
48 
49   return node;
50 }
51 
52 tre_ast_node_t *
tre_ast_new_iter(tre_mem_t mem,tre_ast_node_t * arg,int min,int max,int minimal)53 tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max,
54                      int minimal)
55 {
56   tre_ast_node_t *node;
57   tre_iteration_t *iter;
58 
59   node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t));
60   if (!node)
61     return NULL;
62   iter = node->obj;
63   iter->arg = arg;
64   iter->min = min;
65   iter->max = max;
66   iter->minimal = minimal;
67   node->num_submatches = arg->num_submatches;
68 
69   return node;
70 }
71 
72 tre_ast_node_t *
tre_ast_new_union(tre_mem_t mem,tre_ast_node_t * left,tre_ast_node_t * right)73 tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right)
74 {
75   tre_ast_node_t *node;
76 
77   node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t));
78   if (node == NULL)
79     return NULL;
80   ((tre_union_t *)node->obj)->left = left;
81   ((tre_union_t *)node->obj)->right = right;
82   node->num_submatches = left->num_submatches + right->num_submatches;
83 
84   return node;
85 }
86 
87 tre_ast_node_t *
tre_ast_new_catenation(tre_mem_t mem,tre_ast_node_t * left,tre_ast_node_t * right)88 tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left,
89                            tre_ast_node_t *right)
90 {
91   tre_ast_node_t *node;
92 
93   node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t));
94   if (node == NULL)
95     return NULL;
96   ((tre_catenation_t *)node->obj)->left = left;
97   ((tre_catenation_t *)node->obj)->right = right;
98   node->num_submatches = left->num_submatches + right->num_submatches;
99 
100   return node;
101 }
102 
103 #ifdef TRE_DEBUG
104 
105 static void
tre_findent(FILE * stream,int i)106 tre_findent(FILE *stream, int i)
107 {
108   while (i-- > 0)
109     fputc(' ', stream);
110 }
111 
112 void
tre_print_params(int * params)113 tre_print_params(int *params)
114 {
115   int i;
116   if (params)
117     {
118       DPRINT(("params ["));
119       for (i = 0; i < TRE_PARAM_LAST; i++)
120           {
121             if (params[i] == TRE_PARAM_UNSET)
122               DPRINT(("unset"));
123             else if (params[i] == TRE_PARAM_DEFAULT)
124               DPRINT(("default"));
125             else
126               DPRINT(("%d", params[i]));
127             if (i < TRE_PARAM_LAST - 1)
128               DPRINT((", "));
129           }
130       DPRINT(("]"));
131     }
132 }
133 
134 static void
tre_do_print(FILE * stream,tre_ast_node_t * ast,int indent)135 tre_do_print(FILE *stream, tre_ast_node_t *ast, int indent)
136 {
137   int code_min, code_max, pos;
138   int num_tags = ast->num_tags;
139   tre_literal_t *lit;
140   tre_iteration_t *iter;
141 
142   tre_findent(stream, indent);
143   switch (ast->type)
144     {
145     case LITERAL:
146       lit = ast->obj;
147       code_min = lit->code_min;
148       code_max = lit->code_max;
149       pos = lit->position;
150       if (IS_EMPTY(lit))
151           {
152             fprintf(stream, "literal empty\n");
153           }
154       else if (IS_ASSERTION(lit))
155           {
156             int i;
157             char *assertions[] = { "bol", "eol", "bracket",
158                                          "bow", "eow", "wb", "!wb", "backref" };
159             if (code_max >= ASSERT_LAST << 1)
160               assert(0);
161             fprintf(stream, "assertions: ");
162             for (i = 0; (1 << i) <= ASSERT_LAST; i++)
163               if (code_max & (1 << i))
164                 fprintf(stream, "%s ", assertions[i]);
165             fprintf(stream, "\n");
166           }
167       else if (IS_TAG(lit))
168           {
169             fprintf(stream, "tag %d\n", code_max);
170           }
171       else if (IS_BACKREF(lit))
172           {
173             fprintf(stream, "backref %d, pos %d\n", code_max, pos);
174           }
175       else if (IS_PARAMETER(lit))
176           {
177             tre_print_params(lit->u.params);
178             fprintf(stream, "\n");
179           }
180       else
181           {
182             fprintf(stream, "literal (%c, %c) (%d, %d), pos %d, sub %d, "
183                       "%d tags\n", code_min, code_max, code_min, code_max, pos,
184                       ast->submatch_id, num_tags);
185           }
186       break;
187     case ITERATION:
188       iter = ast->obj;
189       fprintf(stream, "iteration {%d, %d}, sub %d, %d tags, %s\n",
190                 iter->min, iter->max, ast->submatch_id, num_tags,
191                 iter->minimal ? "minimal" : "greedy");
192       tre_do_print(stream, iter->arg, indent + 2);
193       break;
194     case UNION:
195       fprintf(stream, "union, sub %d, %d tags\n", ast->submatch_id, num_tags);
196       tre_do_print(stream, ((tre_union_t *)ast->obj)->left, indent + 2);
197       tre_do_print(stream, ((tre_union_t *)ast->obj)->right, indent + 2);
198       break;
199     case CATENATION:
200       fprintf(stream, "catenation, sub %d, %d tags\n", ast->submatch_id,
201                 num_tags);
202       tre_do_print(stream, ((tre_catenation_t *)ast->obj)->left, indent + 2);
203       tre_do_print(stream, ((tre_catenation_t *)ast->obj)->right, indent + 2);
204       break;
205     default:
206       assert(0);
207       break;
208     }
209 }
210 
211 static void
tre_ast_fprint(FILE * stream,tre_ast_node_t * ast)212 tre_ast_fprint(FILE *stream, tre_ast_node_t *ast)
213 {
214   tre_do_print(stream, ast, 0);
215 }
216 
217 void
tre_ast_print(tre_ast_node_t * tree)218 tre_ast_print(tre_ast_node_t *tree)
219 {
220   printf("AST:\n");
221   tre_ast_fprint(stdout, tree);
222 }
223 
224 #endif /* TRE_DEBUG */
225 
226 /* EOF */
227