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