xref: /aosp_15_r20/external/openscreen/tools/cddl/main.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2018 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include <fcntl.h>
6*3f982cf4SFabien Sanglard #include <string.h>
7*3f982cf4SFabien Sanglard #include <unistd.h>
8*3f982cf4SFabien Sanglard 
9*3f982cf4SFabien Sanglard #include <fstream>
10*3f982cf4SFabien Sanglard #include <iostream>
11*3f982cf4SFabien Sanglard #include <string>
12*3f982cf4SFabien Sanglard #include <vector>
13*3f982cf4SFabien Sanglard 
14*3f982cf4SFabien Sanglard #include "tools/cddl/codegen.h"
15*3f982cf4SFabien Sanglard #include "tools/cddl/logging.h"
16*3f982cf4SFabien Sanglard #include "tools/cddl/parse.h"
17*3f982cf4SFabien Sanglard #include "tools/cddl/sema.h"
18*3f982cf4SFabien Sanglard 
ReadEntireFile(const std::string & filename)19*3f982cf4SFabien Sanglard std::string ReadEntireFile(const std::string& filename) {
20*3f982cf4SFabien Sanglard   std::ifstream input(filename);
21*3f982cf4SFabien Sanglard   if (!input) {
22*3f982cf4SFabien Sanglard     return {};
23*3f982cf4SFabien Sanglard   }
24*3f982cf4SFabien Sanglard 
25*3f982cf4SFabien Sanglard   input.seekg(0, std::ios_base::end);
26*3f982cf4SFabien Sanglard   size_t length = input.tellg();
27*3f982cf4SFabien Sanglard   std::string input_data(length + 1, 0);
28*3f982cf4SFabien Sanglard 
29*3f982cf4SFabien Sanglard   input.seekg(0, std::ios_base::beg);
30*3f982cf4SFabien Sanglard   input.read(const_cast<char*>(input_data.data()), length);
31*3f982cf4SFabien Sanglard   input_data[length] = 0;
32*3f982cf4SFabien Sanglard 
33*3f982cf4SFabien Sanglard   return input_data;
34*3f982cf4SFabien Sanglard }
35*3f982cf4SFabien Sanglard 
36*3f982cf4SFabien Sanglard struct CommandLineArguments {
37*3f982cf4SFabien Sanglard   std::string header_filename;
38*3f982cf4SFabien Sanglard   std::string cc_filename;
39*3f982cf4SFabien Sanglard   std::string gen_dir;
40*3f982cf4SFabien Sanglard   std::string cddl_filename;
41*3f982cf4SFabien Sanglard };
42*3f982cf4SFabien Sanglard 
ParseCommandLineArguments(int argc,char ** argv)43*3f982cf4SFabien Sanglard CommandLineArguments ParseCommandLineArguments(int argc, char** argv) {
44*3f982cf4SFabien Sanglard   --argc;
45*3f982cf4SFabien Sanglard   ++argv;
46*3f982cf4SFabien Sanglard   CommandLineArguments result;
47*3f982cf4SFabien Sanglard   while (argc) {
48*3f982cf4SFabien Sanglard     if (strcmp(*argv, "--header") == 0) {
49*3f982cf4SFabien Sanglard       // Parse the filename of the output header file. This is also the name
50*3f982cf4SFabien Sanglard       // that will be used for the include guard and as the  include path in the
51*3f982cf4SFabien Sanglard       // source file.
52*3f982cf4SFabien Sanglard       if (!result.header_filename.empty()) {
53*3f982cf4SFabien Sanglard         return {};
54*3f982cf4SFabien Sanglard       }
55*3f982cf4SFabien Sanglard       if (!argc) {
56*3f982cf4SFabien Sanglard         return {};
57*3f982cf4SFabien Sanglard       }
58*3f982cf4SFabien Sanglard       --argc;
59*3f982cf4SFabien Sanglard       ++argv;
60*3f982cf4SFabien Sanglard       result.header_filename = *argv;
61*3f982cf4SFabien Sanglard     } else if (strcmp(*argv, "--cc") == 0) {
62*3f982cf4SFabien Sanglard       // Parse the filename of the output source file.
63*3f982cf4SFabien Sanglard       if (!result.cc_filename.empty()) {
64*3f982cf4SFabien Sanglard         return {};
65*3f982cf4SFabien Sanglard       }
66*3f982cf4SFabien Sanglard       if (!argc) {
67*3f982cf4SFabien Sanglard         return {};
68*3f982cf4SFabien Sanglard       }
69*3f982cf4SFabien Sanglard       --argc;
70*3f982cf4SFabien Sanglard       ++argv;
71*3f982cf4SFabien Sanglard       result.cc_filename = *argv;
72*3f982cf4SFabien Sanglard     } else if (strcmp(*argv, "--gen-dir") == 0) {
73*3f982cf4SFabien Sanglard       // Parse the directory prefix that should be added to the output header.
74*3f982cf4SFabien Sanglard       // and source file
75*3f982cf4SFabien Sanglard       if (!result.gen_dir.empty()) {
76*3f982cf4SFabien Sanglard         return {};
77*3f982cf4SFabien Sanglard       }
78*3f982cf4SFabien Sanglard       if (!argc) {
79*3f982cf4SFabien Sanglard         return {};
80*3f982cf4SFabien Sanglard       }
81*3f982cf4SFabien Sanglard       --argc;
82*3f982cf4SFabien Sanglard       ++argv;
83*3f982cf4SFabien Sanglard       result.gen_dir = *argv;
84*3f982cf4SFabien Sanglard     } else if (!result.cddl_filename.empty()) {
85*3f982cf4SFabien Sanglard       return {};
86*3f982cf4SFabien Sanglard     } else {
87*3f982cf4SFabien Sanglard       // The input file which contains the CDDL spec.
88*3f982cf4SFabien Sanglard       result.cddl_filename = *argv;
89*3f982cf4SFabien Sanglard     }
90*3f982cf4SFabien Sanglard     --argc;
91*3f982cf4SFabien Sanglard     ++argv;
92*3f982cf4SFabien Sanglard   }
93*3f982cf4SFabien Sanglard 
94*3f982cf4SFabien Sanglard   // If one of the required properties is missed, return empty. Else, return
95*3f982cf4SFabien Sanglard   // generated struct.
96*3f982cf4SFabien Sanglard   if (result.header_filename.empty() || result.cc_filename.empty() ||
97*3f982cf4SFabien Sanglard       result.gen_dir.empty() || result.cddl_filename.empty()) {
98*3f982cf4SFabien Sanglard     return {};
99*3f982cf4SFabien Sanglard   }
100*3f982cf4SFabien Sanglard   return result;
101*3f982cf4SFabien Sanglard }
102*3f982cf4SFabien Sanglard 
main(int argc,char ** argv)103*3f982cf4SFabien Sanglard int main(int argc, char** argv) {
104*3f982cf4SFabien Sanglard   // Parse and validate all cmdline arguments.
105*3f982cf4SFabien Sanglard   CommandLineArguments args = ParseCommandLineArguments(argc, argv);
106*3f982cf4SFabien Sanglard   if (args.cddl_filename.empty()) {
107*3f982cf4SFabien Sanglard     std::cerr << "Usage: " << std::endl
108*3f982cf4SFabien Sanglard               << "cddl --header parsed.h --cc parsed.cc --gen-dir "
109*3f982cf4SFabien Sanglard                  "output/generated input.cddl"
110*3f982cf4SFabien Sanglard               << std::endl
111*3f982cf4SFabien Sanglard               << "All flags are required." << std::endl
112*3f982cf4SFabien Sanglard               << "Example: " << std::endl
113*3f982cf4SFabien Sanglard               << "./cddl --header osp_messages.h --cc osp_messages.cc "
114*3f982cf4SFabien Sanglard                  "--gen-dir gen/msgs ../../msgs/osp_messages.cddl"
115*3f982cf4SFabien Sanglard               << std::endl;
116*3f982cf4SFabien Sanglard     return 1;
117*3f982cf4SFabien Sanglard   }
118*3f982cf4SFabien Sanglard 
119*3f982cf4SFabien Sanglard   size_t pos = args.cddl_filename.find_last_of('.');
120*3f982cf4SFabien Sanglard   if (pos == std::string::npos) {
121*3f982cf4SFabien Sanglard     return 1;
122*3f982cf4SFabien Sanglard   }
123*3f982cf4SFabien Sanglard 
124*3f982cf4SFabien Sanglard   // Validate and open the provided header file.
125*3f982cf4SFabien Sanglard   std::string header_filename = args.gen_dir + "/" + args.header_filename;
126*3f982cf4SFabien Sanglard   int header_fd = open(header_filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
127*3f982cf4SFabien Sanglard                        S_IRUSR | S_IWUSR | S_IRGRP);
128*3f982cf4SFabien Sanglard   if (header_fd == -1) {
129*3f982cf4SFabien Sanglard     std::cerr << "failed to open " << args.header_filename << std::endl;
130*3f982cf4SFabien Sanglard     return 1;
131*3f982cf4SFabien Sanglard   }
132*3f982cf4SFabien Sanglard 
133*3f982cf4SFabien Sanglard   // Validate and open the provided output source file.
134*3f982cf4SFabien Sanglard   std::string cc_filename = args.gen_dir + "/" + args.cc_filename;
135*3f982cf4SFabien Sanglard   int cc_fd = open(cc_filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
136*3f982cf4SFabien Sanglard                    S_IRUSR | S_IWUSR | S_IRGRP);
137*3f982cf4SFabien Sanglard   if (cc_fd == -1) {
138*3f982cf4SFabien Sanglard     std::cerr << "failed to open " << args.cc_filename << std::endl;
139*3f982cf4SFabien Sanglard     return 1;
140*3f982cf4SFabien Sanglard   }
141*3f982cf4SFabien Sanglard 
142*3f982cf4SFabien Sanglard   // Read and parse the CDDL spec file.
143*3f982cf4SFabien Sanglard   std::string data = ReadEntireFile(args.cddl_filename);
144*3f982cf4SFabien Sanglard   if (data.empty()) {
145*3f982cf4SFabien Sanglard     return 1;
146*3f982cf4SFabien Sanglard   }
147*3f982cf4SFabien Sanglard 
148*3f982cf4SFabien Sanglard   Logger::Log("Successfully initialized CDDL Code generator!");
149*3f982cf4SFabien Sanglard 
150*3f982cf4SFabien Sanglard   // Parse the full CDDL into a graph structure.
151*3f982cf4SFabien Sanglard   Logger::Log("Parsing CDDL input file...");
152*3f982cf4SFabien Sanglard   ParseResult parse_result = ParseCddl(data);
153*3f982cf4SFabien Sanglard   if (!parse_result.root) {
154*3f982cf4SFabien Sanglard     Logger::Error("Failed to parse CDDL input file");
155*3f982cf4SFabien Sanglard     return 1;
156*3f982cf4SFabien Sanglard   }
157*3f982cf4SFabien Sanglard   Logger::Log("Successfully parsed CDDL input file!");
158*3f982cf4SFabien Sanglard 
159*3f982cf4SFabien Sanglard   // Build the Symbol table from this graph structure.
160*3f982cf4SFabien Sanglard   Logger::Log("Generating CDDL Symbol Table...");
161*3f982cf4SFabien Sanglard   std::pair<bool, CddlSymbolTable> cddl_result =
162*3f982cf4SFabien Sanglard       BuildSymbolTable(*parse_result.root);
163*3f982cf4SFabien Sanglard   if (!cddl_result.first) {
164*3f982cf4SFabien Sanglard     Logger::Error("Failed to generate CDDL symbol table");
165*3f982cf4SFabien Sanglard     return 1;
166*3f982cf4SFabien Sanglard   }
167*3f982cf4SFabien Sanglard   Logger::Log("Successfully generated CDDL symbol table!");
168*3f982cf4SFabien Sanglard 
169*3f982cf4SFabien Sanglard   Logger::Log("Generating CPP symbol table...");
170*3f982cf4SFabien Sanglard   std::pair<bool, CppSymbolTable> cpp_result =
171*3f982cf4SFabien Sanglard       BuildCppTypes(cddl_result.second);
172*3f982cf4SFabien Sanglard   if (!cpp_result.first) {
173*3f982cf4SFabien Sanglard     Logger::Error("Failed to generate CPP symbol table");
174*3f982cf4SFabien Sanglard     return 1;
175*3f982cf4SFabien Sanglard   }
176*3f982cf4SFabien Sanglard   Logger::Log("Successfully generated CPP symbol table!");
177*3f982cf4SFabien Sanglard 
178*3f982cf4SFabien Sanglard   // Validate that the provided CDDL doesnt have duplicated indices.
179*3f982cf4SFabien Sanglard   if (!ValidateCppTypes(cpp_result.second)) {
180*3f982cf4SFabien Sanglard     return 1;
181*3f982cf4SFabien Sanglard   }
182*3f982cf4SFabien Sanglard 
183*3f982cf4SFabien Sanglard   // Create the C++ files from the Symbol table.
184*3f982cf4SFabien Sanglard 
185*3f982cf4SFabien Sanglard   Logger::Log("Writing Header prologue...");
186*3f982cf4SFabien Sanglard   if (!WriteHeaderPrologue(header_fd, args.header_filename)) {
187*3f982cf4SFabien Sanglard     Logger::Error("WriteHeaderPrologue failed");
188*3f982cf4SFabien Sanglard     return 1;
189*3f982cf4SFabien Sanglard   }
190*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote header prologue!");
191*3f982cf4SFabien Sanglard 
192*3f982cf4SFabien Sanglard   Logger::Log("Writing type definitions...");
193*3f982cf4SFabien Sanglard   if (!WriteTypeDefinitions(header_fd, &cpp_result.second)) {
194*3f982cf4SFabien Sanglard     Logger::Error("WriteTypeDefinitions failed");
195*3f982cf4SFabien Sanglard     return 1;
196*3f982cf4SFabien Sanglard   }
197*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote type definitions!");
198*3f982cf4SFabien Sanglard 
199*3f982cf4SFabien Sanglard   Logger::Log("Writing function declaration...");
200*3f982cf4SFabien Sanglard   if (!WriteFunctionDeclarations(header_fd, &cpp_result.second)) {
201*3f982cf4SFabien Sanglard     Logger::Error("WriteFunctionDeclarations failed");
202*3f982cf4SFabien Sanglard     return 1;
203*3f982cf4SFabien Sanglard   }
204*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote function declarations!");
205*3f982cf4SFabien Sanglard 
206*3f982cf4SFabien Sanglard   Logger::Log("Writing header epilogue...");
207*3f982cf4SFabien Sanglard   if (!WriteHeaderEpilogue(header_fd, args.header_filename)) {
208*3f982cf4SFabien Sanglard     Logger::Error("WriteHeaderEpilogue failed");
209*3f982cf4SFabien Sanglard     return 1;
210*3f982cf4SFabien Sanglard   }
211*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote header epilogue!");
212*3f982cf4SFabien Sanglard 
213*3f982cf4SFabien Sanglard   Logger::Log("Writing source prologue...");
214*3f982cf4SFabien Sanglard   if (!WriteSourcePrologue(cc_fd, args.header_filename)) {
215*3f982cf4SFabien Sanglard     Logger::Error("WriteSourcePrologue failed");
216*3f982cf4SFabien Sanglard     return 1;
217*3f982cf4SFabien Sanglard   }
218*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote source prologue!");
219*3f982cf4SFabien Sanglard 
220*3f982cf4SFabien Sanglard   Logger::Log("Writing encoders...");
221*3f982cf4SFabien Sanglard   if (!WriteEncoders(cc_fd, &cpp_result.second)) {
222*3f982cf4SFabien Sanglard     Logger::Error("WriteEncoders failed");
223*3f982cf4SFabien Sanglard     return 1;
224*3f982cf4SFabien Sanglard   }
225*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote encoders!");
226*3f982cf4SFabien Sanglard 
227*3f982cf4SFabien Sanglard   Logger::Log("Writing decoders...");
228*3f982cf4SFabien Sanglard   if (!WriteDecoders(cc_fd, &cpp_result.second)) {
229*3f982cf4SFabien Sanglard     Logger::Error("WriteDecoders failed");
230*3f982cf4SFabien Sanglard     return 1;
231*3f982cf4SFabien Sanglard   }
232*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote decoders!");
233*3f982cf4SFabien Sanglard 
234*3f982cf4SFabien Sanglard   Logger::Log("Writing equality operators...");
235*3f982cf4SFabien Sanglard   if (!WriteEqualityOperators(cc_fd, &cpp_result.second)) {
236*3f982cf4SFabien Sanglard     Logger::Error("WriteStructEqualityOperators failed");
237*3f982cf4SFabien Sanglard     return 1;
238*3f982cf4SFabien Sanglard   }
239*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote equality operators!");
240*3f982cf4SFabien Sanglard 
241*3f982cf4SFabien Sanglard   Logger::Log("Writing source epilogue...");
242*3f982cf4SFabien Sanglard   if (!WriteSourceEpilogue(cc_fd)) {
243*3f982cf4SFabien Sanglard     Logger::Error("WriteSourceEpilogue failed");
244*3f982cf4SFabien Sanglard     return 1;
245*3f982cf4SFabien Sanglard   }
246*3f982cf4SFabien Sanglard   Logger::Log("Successfully wrote source epilogue!");
247*3f982cf4SFabien Sanglard 
248*3f982cf4SFabien Sanglard   close(header_fd);
249*3f982cf4SFabien Sanglard   close(cc_fd);
250*3f982cf4SFabien Sanglard   Logger::Log("SUCCESSFULLY COMPLETED ALL OPERATIONS");
251*3f982cf4SFabien Sanglard 
252*3f982cf4SFabien Sanglard   return 0;
253*3f982cf4SFabien Sanglard }
254