]> git.draconx.ca Git - cdecl99.git/blob - src/declare.c
Separate specifier handling from the output routines.
[cdecl99.git] / src / declare.c
1 /*
2  *  Render C declarations.
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 <config.h>
19 #include <stdio.h>
20 #include <assert.h>
21
22 #include "cdecl.h"
23 #include "output.h"
24
25 static size_t declare_specs(char *buf, size_t n, struct cdecl_declspec *s)
26 {
27         size_t ret = 0, rc;
28
29         if (!s)
30                 return 0;
31
32         rc = cdecl__explain_pre_specs(buf, n, s);
33         ret += cdecl__advance(&buf, &n, rc);
34
35         rc = cdecl__explain_post_specs(buf, n, s);
36         return ret + rc;
37 }
38
39 static size_t
40 declare_declarator(char *buf, size_t n, struct cdecl_declarator *d);
41
42 static size_t declare_decl(char *buf, size_t n, struct cdecl *decl)
43 {
44         size_t ret = 0, rc;
45
46         rc = declare_specs(buf, n, decl->specifiers);
47         if (decl->declarators->type != CDECL_DECL_NULL)
48                 ret += cdecl__advance(&buf, &n, rc);
49         else
50                 ret += cdecl__advance_(&buf, &n, rc);
51
52         return ret + declare_declarator(buf, n, decl->declarators);
53 }
54
55 static size_t
56 declare_postfix_child(char *buf, size_t n, struct cdecl_declarator *d)
57 {
58         size_t ret = 0, rc;
59
60         if (d->type == CDECL_DECL_POINTER) {
61                 rc = snprintf(buf, n, "(");
62                 ret += cdecl__advance_(&buf, &n, rc);
63         }
64
65         rc = declare_declarator(buf, n, d);
66         ret += cdecl__advance_(&buf, &n, rc);
67
68         if (d->type == CDECL_DECL_POINTER) {
69                 rc = snprintf(buf, n, ")");
70                 ret += cdecl__advance_(&buf, &n, rc);
71         }
72
73         return ret;
74 }
75
76 static size_t declare_pointer(char *buf, size_t n, struct cdecl_pointer *p)
77 {
78         size_t ret = 0, rc;
79
80         rc = snprintf(buf, n, "*");
81         if (p->qualifiers)
82                 ret += cdecl__advance(&buf, &n, rc);
83         else
84                 ret += cdecl__advance_(&buf, &n, rc);
85
86         rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
87         return ret + cdecl__advance(&buf, &n, rc);
88 }
89
90 static size_t declare_array(char *buf, size_t n, struct cdecl_array *a)
91 {
92         size_t ret = 0, rc;
93
94         rc = snprintf(buf, n, "[");
95         ret += cdecl__advance_(&buf, &n, rc);
96
97         if (a->vla)
98                 rc = snprintf(buf, n, "%s", a->vla[0] ? a->vla : "*");
99         else
100                 rc = snprintf(buf, n, "%.0ju", a->length);
101         ret += cdecl__advance_(&buf, &n, rc);
102
103         return ret + snprintf(buf, n, "]");
104 }
105
106 static size_t declare_function(char *buf, size_t n, struct cdecl_function *f)
107 {
108         size_t ret = 0, rc;
109
110         rc = snprintf(buf, n, "(");
111         ret += cdecl__advance_(&buf, &n, rc);
112
113         for (struct cdecl *p = f->parameters; p; p = p->next) {
114                 rc = declare_decl(buf, n, p);
115                 ret += cdecl__advance_(&buf, &n, rc);
116
117                 rc = 0;
118                 if (p->next)
119                         rc = snprintf(buf, n, ", ");
120                 else if (f->variadic)
121                         rc = snprintf(buf, n, ", ...");
122                 ret += cdecl__advance_(&buf, &n, rc);
123         }
124
125         return ret + snprintf(buf, n, ")");
126 }
127
128 static size_t
129 declare_declarator(char *buf, size_t n, struct cdecl_declarator *d)
130 {
131         size_t ret = 0, rc;
132
133         for (; d; d = d->child) {
134                 switch (d->type) {
135                 case CDECL_DECL_NULL:
136                         break;
137                 case CDECL_DECL_IDENT:
138                         rc = snprintf(buf, n, "%s", d->u.ident);
139                         ret += cdecl__advance_(&buf, &n, rc);
140                         break;
141                 case CDECL_DECL_POINTER:
142                         rc = declare_pointer(buf, n, &d->u.pointer);
143                         ret += cdecl__advance_(&buf, &n, rc);
144                         break;
145                 /*
146                  * Arrays and functions are special: since they are postfix,
147                  * we need to render the children before rendering their
148                  * "bodies".
149                  */
150                 case CDECL_DECL_ARRAY:
151                         rc = declare_postfix_child(buf, n, d->child);
152                         ret += cdecl__advance_(&buf, &n, rc);
153                         return ret + declare_array(buf, n, &d->u.array);
154                 case CDECL_DECL_FUNCTION:
155                         rc = declare_postfix_child(buf, n, d->child);
156                         ret += cdecl__advance_(&buf, &n, rc);
157                         return ret + declare_function(buf, n, &d->u.function);
158                 default:
159                         assert(0);
160                 }
161         }
162
163         return ret;
164 }
165
166 size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl)
167 {
168         return declare_decl(buf, n, decl);
169 }