]> git.draconx.ca Git - cdecl99.git/blob - src/explain.c
877d6db511363437253a6f9b912aa85199a8dfd9
[cdecl99.git] / src / explain.c
1 /*
2  *  Render C declarations as English.
3  *  Copyright © 2011, 2021, 2023 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 <inttypes.h>
24 #include <stdbool.h>
25 #include <assert.h>
26
27 #include "cdecl.h"
28 #include "cdecl-internal.h"
29
30 static size_t explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
31 {
32         return cdecl__explain_specs(buf, n, s, CDECL_SPEC_FUNC|CDECL_SPEC_STOR);
33 }
34
35 static size_t explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
36 {
37         return cdecl__explain_specs(buf, n, s, CDECL_SPEC_QUAL|CDECL_SPEC_TYPE);
38 }
39
40 /*
41  * Renders the start of the thing being declared.  If top is true, print
42  * the "declare" or "type" keywords at the front, as appropriate.
43  */
44 static size_t
45 explain_prologue(char *buf, size_t n, struct cdecl_declarator *d, bool top)
46 {
47         size_t ret = 0, rc = 0;
48
49         while (d) {
50                 switch (d->type) {
51                 case CDECL_DECL_NULL:
52                         if (top)
53                                 return snprintf(buf, n, "type");
54                         return 0;
55                 case CDECL_DECL_IDENT:
56                         if (top)
57                                 rc = snprintf(buf, n, "declare");
58                         ret += cdecl__advance(&buf, &n, rc);
59                         return ret + snprintf(buf, n, "%s as", d->u.ident);
60                 }
61
62                 d = d->child;
63         }
64
65         assert(0);
66 }
67
68 static size_t
69 explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
70 {
71         size_t ret = 0, rc;
72
73         rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
74         ret += cdecl__advance(&buf, &n, rc);
75
76         return ret + snprintf(buf, n, "pointer to");
77 }
78
79 static size_t
80 explain_array(char *buf, size_t n, struct cdecl_array *a)
81 {
82         size_t ret = 0, rc = 0;
83
84         if (a->vla)
85                 rc = snprintf(buf, n, "variable-length array");
86         else
87                 rc = snprintf(buf, n, "array");
88         ret += cdecl__advance(&buf, &n, rc);
89
90         if (a->vla) {
91                 rc = snprintf(buf, n, "%s", a->vla);
92                 ret += cdecl__advance(&buf, &n, rc);
93         } else if (a->length) {
94                 rc = snprintf(buf, n, "%" PRIuMAX, a->length);
95                 ret += cdecl__advance(&buf, &n, rc);
96         }
97
98         return ret + snprintf(buf, n, "of");
99 }
100
101 static size_t
102 explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl);
103
104 static size_t explain_decl(char *buf, size_t n, struct cdecl *decl, bool top)
105 {
106         size_t ret = 0, rc;
107
108         rc = explain_prologue(buf, n, decl->declarators, top);
109         ret += cdecl__advance(&buf, &n, rc);
110
111         rc = explain_pre_specs(buf, n, decl->specifiers);
112         ret += cdecl__advance(&buf, &n, rc);
113
114         rc = explain_declarators(buf, n, decl->declarators);
115         ret += cdecl__advance(&buf, &n, rc);
116
117         return ret + explain_post_specs(buf, n, decl->specifiers);
118 }
119
120 static size_t explain_function(char *buf, size_t n, struct cdecl_function *f)
121 {
122         size_t ret = 0, rc = 0;
123
124         rc = snprintf(buf, n, "function");
125         ret += cdecl__advance(&buf, &n, rc);
126
127         if (f->parameters) {
128                 rc = snprintf(buf, n, "(");
129                 ret += cdecl__advance_(&buf, &n, rc);
130
131                 for (struct cdecl *p = f->parameters; p; p = p->next) {
132                         rc = explain_decl(buf, n, p, false);
133                         ret += cdecl__advance_(&buf, &n, rc);
134
135                         if (p->next)
136                                 rc = snprintf(buf, n, ",");
137                         else if (f->variadic)
138                                 rc = snprintf(buf, n, ", ...)");
139                         else
140                                 rc = snprintf(buf, n, ")");
141                         ret += cdecl__advance(&buf, &n, rc);
142                 }
143         }
144
145         return ret + snprintf(buf, n, "returning");
146 }
147
148 static size_t
149 explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
150 {
151         size_t ret = 0, rc;
152
153         if (d->type == CDECL_DECL_IDENT || d->type == CDECL_DECL_NULL)
154                 return 0;
155
156         rc = explain_declarators(buf, n, d->child);
157         ret += cdecl__advance(&buf, &n, rc);
158
159         switch (d->type) {
160         case CDECL_DECL_POINTER:
161                 return ret + explain_pointer(buf, n, &d->u.pointer);
162         case CDECL_DECL_ARRAY:
163                 return ret + explain_array(buf, n, &d->u.array);
164         case CDECL_DECL_FUNCTION:
165                 return ret + explain_function(buf, n, &d->u.function);
166         default:
167                 assert(0);
168         }
169 }
170
171 size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl)
172 {
173         return explain_decl(buf, n, decl, true);
174 }