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