]> git.draconx.ca Git - cdecl99.git/blob - src/explain.c
0f6b787afcb135122187322b668eb6f35813aa37
[cdecl99.git] / src / explain.c
1 /*
2  *  Render C declarations as English.
3  *  Copyright © 2011, 2021 Nick Bowler
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <assert.h>
25
26 #include "cdecl.h"
27 #include "cdecl-internal.h"
28
29 /*
30  * Renders the start of the thing being declared.  If top is true, print
31  * the "declare" or "type" keywords at the front, as appropriate.
32  */
33 static size_t
34 explain_prologue(char *buf, size_t n, struct cdecl_declarator *d, bool top)
35 {
36         size_t ret = 0, rc = 0;
37
38         while (d) {
39                 switch (d->type) {
40                 case CDECL_DECL_NULL:
41                         if (top)
42                                 return snprintf(buf, n, "type");
43                         return 0;
44                 case CDECL_DECL_IDENT:
45                         if (top)
46                                 rc = snprintf(buf, n, "declare");
47                         ret += cdecl__advance(&buf, &n, rc);
48                         return ret + snprintf(buf, n, "%s as", d->u.ident);
49                 }
50
51                 d = d->child;
52         }
53
54         assert(0);
55 }
56
57 static size_t
58 explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
59 {
60         size_t ret = 0, rc;
61
62         rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
63         ret += cdecl__advance(&buf, &n, rc);
64
65         return ret + snprintf(buf, n, "pointer to");
66 }
67
68 static size_t
69 explain_array(char *buf, size_t n, struct cdecl_array *a)
70 {
71         size_t ret = 0, rc = 0;
72
73         if (a->vla)
74                 rc = snprintf(buf, n, "variable-length array");
75         else
76                 rc = snprintf(buf, n, "array");
77         ret += cdecl__advance(&buf, &n, rc);
78
79         if (a->vla) {
80                 rc = snprintf(buf, n, "%s", a->vla);
81                 ret += cdecl__advance(&buf, &n, rc);
82         } else if (a->length) {
83                 rc = snprintf(buf, n, "%ju", a->length);
84                 ret += cdecl__advance(&buf, &n, rc);
85         }
86
87         return ret + snprintf(buf, n, "of");
88 }
89
90 static size_t
91 explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl);
92
93 static size_t explain_decl(char *buf, size_t n, struct cdecl *decl, bool top)
94 {
95         size_t ret = 0, rc;
96
97         rc = explain_prologue(buf, n, decl->declarators, top);
98         ret += cdecl__advance(&buf, &n, rc);
99
100         rc = cdecl__explain_pre_specs(buf, n, decl->specifiers);
101         ret += cdecl__advance(&buf, &n, rc);
102
103         rc = explain_declarators(buf, n, decl->declarators);
104         ret += cdecl__advance(&buf, &n, rc);
105
106         return ret + cdecl__explain_post_specs(buf, n, decl->specifiers);
107 }
108
109 static size_t explain_function(char *buf, size_t n, struct cdecl_function *f)
110 {
111         size_t ret = 0, rc = 0;
112
113         rc = snprintf(buf, n, "function");
114         ret += cdecl__advance(&buf, &n, rc);
115
116         if (f->parameters) {
117                 rc = snprintf(buf, n, "(");
118                 ret += cdecl__advance_(&buf, &n, rc);
119
120                 for (struct cdecl *p = f->parameters; p; p = p->next) {
121                         rc = explain_decl(buf, n, p, false);
122                         ret += cdecl__advance_(&buf, &n, rc);
123
124                         if (p->next)
125                                 rc = snprintf(buf, n, ",");
126                         else if (f->variadic)
127                                 rc = snprintf(buf, n, ", ...)");
128                         else
129                                 rc = snprintf(buf, n, ")");
130                         ret += cdecl__advance(&buf, &n, rc);
131                 }
132         }
133
134         return ret + snprintf(buf, n, "returning");
135 }
136
137 static size_t
138 explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
139 {
140         size_t ret = 0, rc;
141
142         if (d->type == CDECL_DECL_IDENT || d->type == CDECL_DECL_NULL)
143                 return 0;
144
145         rc = explain_declarators(buf, n, d->child);
146         ret += cdecl__advance(&buf, &n, rc);
147
148         switch (d->type) {
149         case CDECL_DECL_POINTER:
150                 return ret + explain_pointer(buf, n, &d->u.pointer);
151         case CDECL_DECL_ARRAY:
152                 return ret + explain_array(buf, n, &d->u.array);
153         case CDECL_DECL_FUNCTION:
154                 return ret + explain_function(buf, n, &d->u.function);
155         default:
156                 assert(0);
157         }
158 }
159
160 size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl)
161 {
162         return explain_decl(buf, n, decl, true);
163 }