1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #include "lalr.h" |
5 | #include "dotgraph.h" |
6 | #include "parsetable.h" |
7 | #include "cppgenerator.h" |
8 | #include "recognizer.h" |
9 | |
10 | #include <QtCore/qcoreapplication.h> |
11 | #include <QtCore/qfile.h> |
12 | #include <QtCore/qstringlist.h> |
13 | #include <QtCore/qdebug.h> |
14 | |
15 | #include <cstdlib> |
16 | |
17 | #define QLALR_NO_DEBUG_TABLE |
18 | #define QLALR_NO_DEBUG_DOT |
19 | |
20 | using namespace Qt::StringLiterals; |
21 | |
22 | static void help_me () |
23 | { |
24 | qerr() << "Usage: qlalr [options] [input file name]" << Qt::endl |
25 | << Qt::endl |
26 | << " --help, -h\t\tdisplay this help and exit" << Qt::endl |
27 | << " --verbose, -v\t\tverbose output" << Qt::endl |
28 | << " --no-debug\t\tno debug information" << Qt::endl |
29 | << " --no-lines\t\tno #line directives" << Qt::endl |
30 | << " --dot\t\t\tgenerate a graph" << Qt::endl |
31 | << " --qt\t\t\tadd the Qt copyright header and Qt-specific types and macros" << Qt::endl |
32 | << " --exit-on-warn\texit with status code 2 on warning" << Qt::endl |
33 | << Qt::endl; |
34 | exit (status: 0); |
35 | } |
36 | |
37 | int main (int argc, char *argv[]) |
38 | { |
39 | QCoreApplication app (argc, argv); |
40 | |
41 | bool generate_dot = false; |
42 | bool generate_report = false; |
43 | bool no_lines = false; |
44 | bool debug_info = true; |
45 | bool qt_copyright = false; |
46 | bool warnings_are_errors = false; |
47 | QString file_name; |
48 | |
49 | const QStringList args = app.arguments().mid(pos: 1); |
50 | for (const QString &arg : args) { |
51 | if (arg == "-h"_L1 || arg == "--help"_L1 ) |
52 | help_me (); |
53 | |
54 | else if (arg == "-v"_L1 || arg == "--verbose"_L1 ) |
55 | generate_report = true; |
56 | |
57 | else if (arg == "--dot"_L1 ) |
58 | generate_dot = true; |
59 | |
60 | else if (arg == "--no-lines"_L1 ) |
61 | no_lines = true; |
62 | |
63 | else if (arg == "--no-debug"_L1 ) |
64 | debug_info = false; |
65 | |
66 | else if (arg == "--qt"_L1 ) |
67 | qt_copyright = true; |
68 | |
69 | else if (arg == "--exit-on-warn"_L1 ) |
70 | warnings_are_errors = true; |
71 | |
72 | else if (file_name.isEmpty ()) |
73 | file_name = arg; |
74 | |
75 | else |
76 | qerr() << "*** Warning. Ignore argument `" << arg << "'" << Qt::endl; |
77 | } |
78 | |
79 | if (file_name.isEmpty ()) |
80 | { |
81 | help_me (); |
82 | exit (EXIT_SUCCESS); |
83 | } |
84 | |
85 | Grammar grammar; |
86 | Recognizer p (&grammar, no_lines); |
87 | |
88 | if (! p.parse (input_file: file_name)) |
89 | exit (EXIT_FAILURE); |
90 | |
91 | if (grammar.rules.empty()) |
92 | { |
93 | qerr() << "*** Fatal. No rules!" << Qt::endl; |
94 | exit (EXIT_FAILURE); |
95 | } |
96 | |
97 | else if (grammar.start == grammar.names.end ()) |
98 | { |
99 | qerr() << "*** Fatal. No start symbol!" << Qt::endl; |
100 | exit (EXIT_FAILURE); |
101 | } |
102 | |
103 | grammar.buildExtendedGrammar (); |
104 | grammar.buildRuleMap (); |
105 | |
106 | Automaton aut (&grammar); |
107 | aut.build (); |
108 | |
109 | CppGenerator gen (p, grammar, aut, generate_report); |
110 | gen.setDebugInfo (debug_info); |
111 | gen.setCopyright (qt_copyright); |
112 | gen.setWarningsAreErrors (warnings_are_errors); |
113 | gen (); |
114 | |
115 | if (generate_dot) |
116 | { |
117 | DotGraph genDotFile (qout()); |
118 | genDotFile (&aut); |
119 | } |
120 | |
121 | else if (generate_report) |
122 | { |
123 | ParseTable genParseTable (qout()); |
124 | genParseTable(&aut); |
125 | } |
126 | |
127 | return EXIT_SUCCESS; |
128 | } |
129 | |
130 | QString Recognizer::expand (const QString &text) const |
131 | { |
132 | QString code = text; |
133 | |
134 | if (_M_grammar->start != _M_grammar->names.end ()) |
135 | { |
136 | code = code.replace (before: "$start_id"_L1 , after: QString::number (std::distance (first: _M_grammar->names.begin (), last: _M_grammar->start))); |
137 | code = code.replace (before: "$start"_L1 , after: *_M_grammar->start); |
138 | } |
139 | |
140 | code = code.replace (before: "$header"_L1 , after: _M_grammar->table_name.toLower () + "_p.h"_L1 ); |
141 | |
142 | code = code.replace (before: "$table"_L1 , after: _M_grammar->table_name); |
143 | code = code.replace (before: "$parser"_L1 , after: _M_grammar->table_name); |
144 | |
145 | if (_M_current_rule != _M_grammar->rules.end ()) |
146 | { |
147 | code = code.replace (before: "$rule_number"_L1 , after: QString::number (std::distance (first: _M_grammar->rules.begin (), last: _M_current_rule))); |
148 | code = code.replace (before: "$rule"_L1 , after: *_M_current_rule->lhs); |
149 | } |
150 | |
151 | return code; |
152 | } |
153 | |