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