1 /* Counterexample derivation trees
3 Copyright (C) 2020-2021 Free Software Foundation, Inc.
5 This file is part of Bison, the GNU Compiler Compiler.
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
22 #include "derivation.h"
26 #include <gl_linked_list.h>
35 derivation_list children
;
37 // Color assigned for styling. Guarantees that the derivation is
38 // always displayed with the same color, independently of the order
39 // in which the derivations are traversed.
43 static derivation d_dot
= { -1, NULL
, -1, -1 };
52 derivation_list_append (derivation_list dl
, derivation
*d
)
54 derivation_retain (d
);
55 gl_list_add_last (dl
, d
);
59 derivation_list_prepend (derivation_list dl
, derivation
*d
)
61 derivation_retain (d
);
62 gl_list_add_first (dl
, d
);
65 void derivation_list_free (derivation_list dl
)
68 for (gl_list_iterator_t it
= gl_list_iterator (dl
);
69 derivation_list_next (&it
, &d
);
77 derivation_new (symbol_number sym
, derivation_list children
)
79 derivation
*res
= xmalloc (sizeof *res
);
81 res
->children
= children
;
82 res
->reference_count
= 0;
88 derivation_retain (derivation
*d
)
94 derivation_free (derivation
*d
)
98 derivation_list free_queue
=
99 gl_list_create (GL_LINKED_LIST
, NULL
, NULL
, NULL
, true,
100 1, (const void **)&d
);
101 while (gl_list_size (free_queue
) > 0)
103 derivation
*deriv
= (derivation
*) gl_list_get_at (free_queue
, 0);
104 if (--deriv
->reference_count
== 0)
108 derivation
*child
= NULL
;
109 for (gl_list_iterator_t it
= gl_list_iterator (deriv
->children
);
110 derivation_list_next (&it
, &child
);
113 gl_list_add_last (free_queue
, child
);
114 gl_list_free (deriv
->children
);
118 gl_list_remove_at (free_queue
, 0);
120 gl_list_free (free_queue
);
124 derivation_size (const derivation
*deriv
)
126 if (!deriv
->children
)
129 derivation
*child
= NULL
;
130 for (gl_list_iterator_t it
= gl_list_iterator (deriv
->children
);
131 derivation_list_next (&it
, &child
);
133 size
+= derivation_size (child
);
138 // Longest distance from root to leaf.
140 derivation_depth (const derivation
*deriv
)
144 // Children's depth cannot be 0, even if there are no children
145 // (the case of a derivation with an empty RHS).
148 for (gl_list_iterator_t it
= gl_list_iterator (deriv
->children
);
149 derivation_list_next (&it
, &child
);
151 res
= max_int (res
, derivation_depth (child
));
159 all_spaces (const char *s
)
161 while (c_isspace (*s
))
166 // Printing the derivation as trees without trailing spaces is
167 // painful: we cannot simply pad one "column" before moving to the
172 // ↳ x2 ↳ ε ↳ foo2 ↳ x2
174 // ↳ "X" • ↳ x1 foo4 ↳ "X"
179 // It's hard for a column to know that it's "last" to decide whether
180 // to output the right-padding or not. So when we need to pad on the
181 // right to complete a column, we don't output the spaces, we
182 // accumulate the width of padding in *PADDING.
184 // Each time we actually print something (non space), we flush that
185 // padding. When we _don't_ print something, its width is added to
186 // the current padding.
188 // This function implements this.
190 // When COND is true, put S on OUT, preceded by *PADDING white spaces.
191 // Otherwise add the width to *PADDING. Return the width of S.
193 fputs_if (bool cond
, FILE *out
, int *padding
, const char *s
)
195 int res
= mbswidth (s
, 0);
196 if (cond
&& !all_spaces (s
))
198 fprintf (out
, "%*s%s", *padding
, "", s
);
208 // The width taken to report this derivation recursively down to its
211 derivation_width (const derivation
*deriv
)
215 const symbol
*sym
= symbols
[deriv
->sym
];
216 int self_width
= mbswidth (sym
->tag
, 0);
219 int children_width
= down_arrow_width
;
220 if (gl_list_size (deriv
->children
) == 0)
222 children_width
+= empty_width
;
226 for (gl_list_iterator_t it
= gl_list_iterator (deriv
->children
);
227 derivation_list_next (&it
, &child
);
230 += derivation_separator_width
+ derivation_width (child
);
231 // No separator at the beginning.
232 children_width
-= derivation_separator_width
;
234 return max_int (self_width
, children_width
);
236 else if (deriv
== &d_dot
)
242 const symbol
*sym
= symbols
[deriv
->sym
];
243 return mbswidth (sym
->tag
, 0);
248 // Print DERIV for DEPTH.
250 // The tree is printed from top to bottom with DEPTH ranging from 0 to
251 // the total depth of the tree. DERIV should only printed when we
252 // reach its depth, i.e., then DEPTH is 0.
254 // When DEPTH is 1 and we're on a subderivation, then we print the RHS
255 // of the derivation (in DEPTH 0 we printed its LHS).
257 // Return the "logical printed" width. We might have not have reached
258 // that width, in which case the missing spaces are in *PADDING.
260 derivation_print_tree_impl (const derivation
*deriv
, FILE *out
,
261 int depth
, int *padding
)
263 const int width
= derivation_width (deriv
);
268 const symbol
*sym
= symbols
[deriv
->sym
];
270 snprintf (style
, 20, "cex-%d", deriv
->color
);
272 if (depth
== 0 || depth
== 1)
274 begin_use_class (style
, out
);
275 begin_use_class ("cex-step", out
);
279 res
+= fputs_if (true, out
, padding
, sym
->tag
);
283 res
+= fputs_if (depth
== 1, out
, padding
, down_arrow
);
284 if (gl_list_size (deriv
->children
) == 0)
286 res
+= fputs_if (depth
== 1, out
, padding
, empty
);
291 for (gl_list_iterator_t it
= gl_list_iterator (deriv
->children
);
292 derivation_list_next (&it
, &child
);
296 res
+= fputs_if (depth
== 1, out
, padding
, derivation_separator
);
297 res
+= derivation_print_tree_impl (child
, out
, depth
- 1, padding
);
302 if (depth
== 0 || depth
== 1)
304 end_use_class ("cex-step", out
);
305 end_use_class (style
, out
);
307 *padding
+= width
- res
;
310 else if (deriv
== &d_dot
)
313 begin_use_class ("cex-dot", out
);
314 res
+= fputs_if (depth
== 0, out
, padding
, dot
);
316 end_use_class ("cex-dot", out
);
320 const symbol
*sym
= symbols
[deriv
->sym
];
322 begin_use_class ("cex-leaf", out
);
323 res
+= fputs_if (depth
== 0, out
, padding
, sym
->tag
);
325 end_use_class ("cex-leaf", out
);
331 derivation_print_tree (const derivation
*deriv
, FILE *out
, const char *prefix
)
334 for (int depth
= 0, max_depth
= derivation_depth (deriv
);
335 depth
< max_depth
; ++depth
)
338 fprintf (out
, " %s", prefix
);
339 derivation_print_tree_impl (deriv
, out
, depth
, &padding
);
345 /* Print DERIV, colored according to COUNTER.
346 Return false if nothing is printed. */
348 derivation_print_flat_impl (derivation
*deriv
, FILE *out
,
350 int *counter
, const char *prefix
)
354 const symbol
*sym
= symbols
[deriv
->sym
];
355 deriv
->color
= *counter
;
358 snprintf (style
, 20, "cex-%d", deriv
->color
);
359 begin_use_class (style
, out
);
364 begin_use_class ("cex-step", out
);
365 fprintf (out
, "%s %s [ ", sym
->tag
, arrow
);
366 end_use_class ("cex-step", out
);
371 for (gl_list_iterator_t it
= gl_list_iterator (deriv
->children
);
372 derivation_list_next (&it
, &child
);
375 if (derivation_print_flat_impl (child
, out
,
376 leaves_only
, counter
, prefix
))
381 else if (!leaves_only
)
386 begin_use_class ("cex-step", out
);
391 end_use_class ("cex-step", out
);
393 end_use_class (style
, out
);
396 else if (deriv
== &d_dot
)
399 begin_use_class ("cex-dot", out
);
401 end_use_class ("cex-dot", out
);
406 const symbol
*sym
= symbols
[deriv
->sym
];
407 begin_use_class ("cex-leaf", out
);
408 fprintf (out
, "%s", sym
->tag
);
409 end_use_class ("cex-leaf", out
);
415 derivation_print_flat (const derivation
*deriv
, FILE *out
, const char *prefix
)
419 derivation_print_flat_impl ((derivation
*)deriv
, out
, false, &counter
, "");
424 derivation_print_leaves (const derivation
*deriv
, FILE *out
)
427 derivation_print_flat_impl ((derivation
*)deriv
, out
, true, &counter
, "");
432 derivation_print (const derivation
*deriv
, FILE *out
, const char *prefix
)
434 if (getenv ("YYFLAT"))
435 derivation_print_flat (deriv
, out
, prefix
);
437 derivation_print_tree (deriv
, out
, prefix
);