1 #include "generate_c.h"
2 #include "CLikeGenerator.h"
3 #include "options.h"
4 #include "resources.h"
5 #include <cstddef>
6 #include <iostream>
7 #include <rumur/rumur.h>
8 #include <string>
9 #include <vector>
10
11 using namespace rumur;
12
13 namespace {
14
15 class CGenerator : public CLikeGenerator {
16
17 public:
CGenerator(const std::vector<rumur::Comment> & comments_,std::ostream & out_,bool pack_)18 CGenerator(const std::vector<rumur::Comment> &comments_, std::ostream &out_,
19 bool pack_)
20 : CLikeGenerator(comments_, out_, pack_) {}
21
visit_constdecl(const ConstDecl & n)22 void visit_constdecl(const ConstDecl &n) final {
23 *this << indentation() << "const ";
24
25 // if this constant has an explicit type, use that
26 if (n.type != nullptr) {
27 *this << *n.type;
28
29 } else {
30
31 // otherwise, if it was a previously typedefed enum, use its typedefed
32 // name (to avoid later -Wsign-compare warnings on GCC)
33 const Ptr<TypeExpr> type = n.value->type();
34 auto it = enum_typedefs.find(type->unique_id);
35 if (it != enum_typedefs.end()) {
36 *this << it->second;
37
38 } else { // fallback on the type of the right hand side
39 *this << "__typeof__(" << *n.value << ")";
40 }
41 }
42 *this << " " << n.name << " = " << *n.value << ";";
43 emit_trailing_comments(n);
44 *this << "\n";
45 }
46
visit_function(const Function & n)47 void visit_function(const Function &n) final {
48 *this << indentation();
49 if (n.return_type == nullptr) {
50 *this << "void";
51 } else {
52 *this << *n.return_type;
53 }
54 *this << " " << n.name << "(";
55 if (n.parameters.empty()) {
56 *this << "void";
57 } else {
58 std::string sep;
59 for (const Ptr<VarDecl> &p : n.parameters) {
60 *this << sep << *p->type << " ";
61 // if this is a var parameter, it needs to be a pointer
62 if (!p->readonly) {
63 (void)is_pointer.insert(p->unique_id);
64 *this << "*";
65 }
66 *this << p->name;
67 sep = ", ";
68 }
69 }
70 *this << ") {\n";
71 indent();
72 for (const Ptr<Decl> &d : n.decls) {
73 emit_leading_comments(*d);
74 *this << *d;
75 }
76 for (const Ptr<Stmt> &s : n.body) {
77 emit_leading_comments(*s);
78 *this << *s;
79 }
80 dedent();
81 *this << "}\n";
82 }
83
visit_propertyrule(const PropertyRule & n)84 void visit_propertyrule(const PropertyRule &n) final {
85
86 // function prototype
87 *this << indentation() << "bool " << n.name << "(";
88
89 // parameters
90 if (n.quantifiers.empty()) {
91 *this << "void";
92 } else {
93 std::string sep;
94 for (const Quantifier &q : n.quantifiers) {
95 *this << sep;
96 if (auto t = dynamic_cast<const TypeExprID *>(q.type.get())) {
97 *this << t->name;
98 } else {
99 *this << value_type;
100 }
101 *this << " " << q.name;
102 sep = ", ";
103 }
104 }
105
106 *this << ") {\n";
107 indent();
108
109 // any aliases this property uses
110 for (const Ptr<AliasDecl> &a : n.aliases) {
111 *this << *a;
112 }
113
114 *this << indentation() << "return " << *n.property.expr << ";\n";
115
116 // clean up any aliases we defined
117 for (const Ptr<AliasDecl> &a : n.aliases) {
118 *this << "#undef " << a->name << "\n";
119 }
120
121 dedent();
122 *this << "}\n";
123 }
124
visit_simplerule(const SimpleRule & n)125 void visit_simplerule(const SimpleRule &n) final {
126 *this << indentation() << "bool guard_" << n.name << "(";
127
128 // parameters
129 if (n.quantifiers.empty()) {
130 *this << "void";
131 } else {
132 std::string sep;
133 for (const Quantifier &q : n.quantifiers) {
134 *this << sep;
135 if (auto t = dynamic_cast<const TypeExprID *>(q.type.get())) {
136 *this << t->name;
137 } else {
138 *this << value_type;
139 }
140 *this << " " << q.name;
141 sep = ", ";
142 }
143 }
144
145 *this << ") {\n";
146 indent();
147
148 // any aliases that are defined in an outer scope
149 for (const Ptr<AliasDecl> &a : n.aliases) {
150 *this << *a;
151 }
152
153 *this << indentation() << "return ";
154 if (n.guard == nullptr) {
155 *this << "true";
156 } else {
157 *this << *n.guard;
158 }
159 *this << ";\n";
160
161 // clean up aliases
162 for (const Ptr<AliasDecl> &a : n.aliases) {
163 *this << "#undef " << a->name << "\n";
164 }
165
166 dedent();
167 *this << indentation() << "}\n\n";
168
169 *this << indentation() << "void rule_" << n.name << "(";
170
171 // parameters
172 if (n.quantifiers.empty()) {
173 *this << "void";
174 } else {
175 std::string sep;
176 for (const Quantifier &q : n.quantifiers) {
177 *this << sep;
178 if (auto t = dynamic_cast<const TypeExprID *>(q.type.get())) {
179 *this << t->name;
180 } else {
181 *this << value_type;
182 }
183 *this << " " << q.name;
184 sep = ", ";
185 }
186 }
187
188 *this << ") {\n";
189 indent();
190
191 // aliases, variables, local types, etc.
192 for (const Ptr<AliasDecl> &a : n.aliases) {
193 emit_leading_comments(*a);
194 *this << *a;
195 }
196 for (const Ptr<Decl> &d : n.decls) {
197 emit_leading_comments(*d);
198 *this << *d;
199 }
200
201 for (const Ptr<Stmt> &s : n.body) {
202 emit_leading_comments(*s);
203 *this << *s;
204 }
205
206 // clean up any aliases we defined
207 for (const Ptr<Decl> &d : n.decls) {
208 if (auto a = dynamic_cast<const AliasDecl *>(d.get())) {
209 *this << "#undef " << a->name << "\n";
210 }
211 }
212 for (const Ptr<AliasDecl> &a : n.aliases) {
213 *this << "#undef " << a->name << "\n";
214 }
215
216 dedent();
217 *this << indentation() << "}\n";
218 }
219
visit_startstate(const StartState & n)220 void visit_startstate(const StartState &n) final {
221 *this << indentation() << "void startstate_" << n.name << "(";
222
223 // parameters
224 if (n.quantifiers.empty()) {
225 *this << "void";
226 } else {
227 std::string sep;
228 for (const Quantifier &q : n.quantifiers) {
229 *this << sep;
230 if (auto t = dynamic_cast<const TypeExprID *>(q.type.get())) {
231 *this << t->name;
232 } else {
233 *this << value_type;
234 }
235 *this << " " << q.name;
236 sep = ", ";
237 }
238 }
239
240 *this << ") {\n";
241 indent();
242
243 // aliases, variables, local types, etc.
244 for (const Ptr<AliasDecl> &a : n.aliases) {
245 emit_leading_comments(*a);
246 *this << *a;
247 }
248 for (const Ptr<Decl> &d : n.decls) {
249 emit_leading_comments(*d);
250 *this << *d;
251 }
252
253 for (const Ptr<Stmt> &s : n.body) {
254 emit_leading_comments(*s);
255 *this << *s;
256 }
257
258 // clean up any aliases we defined
259 for (const Ptr<Decl> &d : n.decls) {
260 if (auto a = dynamic_cast<const AliasDecl *>(d.get())) {
261 *this << "#undef " << a->name << "\n";
262 }
263 }
264 for (const Ptr<AliasDecl> &a : n.aliases) {
265 *this << "#undef " << a->name << "\n";
266 }
267
268 dedent();
269 *this << indentation() << "}\n\n";
270 }
271
visit_vardecl(const VarDecl & n)272 void visit_vardecl(const VarDecl &n) final {
273 *this << indentation() << *n.type << " " << n.name << ";";
274 emit_trailing_comments(n);
275 *this << "\n";
276 }
277
278 virtual ~CGenerator() = default;
279 };
280
281 } // namespace
282
generate_c(const Node & n,const std::vector<Comment> & comments,bool pack,std::ostream & out)283 void generate_c(const Node &n, const std::vector<Comment> &comments, bool pack,
284 std::ostream &out) {
285
286 // write the static prefix to the beginning of the source file
287 for (size_t i = 0; i < resources_c_prefix_c_len; i++)
288 out << (char)resources_c_prefix_c[i];
289
290 CGenerator gen(comments, out, pack);
291 gen.dispatch(n);
292 }
293