OptParserEmitter.cpp revision 226586
1226586Sdim//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
2226586Sdim//
3226586Sdim//                     The LLVM Compiler Infrastructure
4226586Sdim//
5226586Sdim// This file is distributed under the University of Illinois Open Source
6226586Sdim// License. See LICENSE.TXT for details.
7226586Sdim//
8226586Sdim//===----------------------------------------------------------------------===//
9226586Sdim
10226586Sdim#include "OptParserEmitter.h"
11226586Sdim#include "llvm/TableGen/Record.h"
12226586Sdim#include "llvm/ADT/STLExtras.h"
13226586Sdimusing namespace llvm;
14226586Sdim
15226586Sdimstatic int StrCmpOptionName(const char *A, const char *B) {
16226586Sdim  char a = *A, b = *B;
17226586Sdim  while (a == b) {
18226586Sdim    if (a == '\0')
19226586Sdim      return 0;
20226586Sdim
21226586Sdim    a = *++A;
22226586Sdim    b = *++B;
23226586Sdim  }
24226586Sdim
25226586Sdim  if (a == '\0') // A is a prefix of B.
26226586Sdim    return 1;
27226586Sdim  if (b == '\0') // B is a prefix of A.
28226586Sdim    return -1;
29226586Sdim
30226586Sdim  // Otherwise lexicographic.
31226586Sdim  return (a < b) ? -1 : 1;
32226586Sdim}
33226586Sdim
34226586Sdimstatic int CompareOptionRecords(const void *Av, const void *Bv) {
35226586Sdim  const Record *A = *(Record**) Av;
36226586Sdim  const Record *B = *(Record**) Bv;
37226586Sdim
38226586Sdim  // Sentinel options precede all others and are only ordered by precedence.
39226586Sdim  bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
40226586Sdim  bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
41226586Sdim  if (ASent != BSent)
42226586Sdim    return ASent ? -1 : 1;
43226586Sdim
44226586Sdim  // Compare options by name, unless they are sentinels.
45226586Sdim  if (!ASent)
46226586Sdim    if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
47226586Sdim                                   B->getValueAsString("Name").c_str()))
48226586Sdim    return Cmp;
49226586Sdim
50226586Sdim  // Then by the kind precedence;
51226586Sdim  int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
52226586Sdim  int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
53226586Sdim  assert(APrec != BPrec && "Options are equivalent!");
54226586Sdim  return APrec < BPrec ? -1 : 1;
55226586Sdim}
56226586Sdim
57226586Sdimstatic const std::string getOptionName(const Record &R) {
58226586Sdim  // Use the record name unless EnumName is defined.
59226586Sdim  if (dynamic_cast<UnsetInit*>(R.getValueInit("EnumName")))
60226586Sdim    return R.getName();
61226586Sdim
62226586Sdim  return R.getValueAsString("EnumName");
63226586Sdim}
64226586Sdim
65226586Sdimstatic raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
66226586Sdim  OS << '"';
67226586Sdim  OS.write_escaped(Str);
68226586Sdim  OS << '"';
69226586Sdim  return OS;
70226586Sdim}
71226586Sdim
72226586Sdimvoid OptParserEmitter::run(raw_ostream &OS) {
73226586Sdim  // Get the option groups and options.
74226586Sdim  const std::vector<Record*> &Groups =
75226586Sdim    Records.getAllDerivedDefinitions("OptionGroup");
76226586Sdim  std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
77226586Sdim
78226586Sdim  if (GenDefs)
79226586Sdim    EmitSourceFileHeader("Option Parsing Definitions", OS);
80226586Sdim  else
81226586Sdim    EmitSourceFileHeader("Option Parsing Table", OS);
82226586Sdim
83226586Sdim  array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
84226586Sdim  if (GenDefs) {
85226586Sdim    OS << "#ifndef OPTION\n";
86226586Sdim    OS << "#error \"Define OPTION prior to including this file!\"\n";
87226586Sdim    OS << "#endif\n\n";
88226586Sdim
89226586Sdim    OS << "/////////\n";
90226586Sdim    OS << "// Groups\n\n";
91226586Sdim    for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
92226586Sdim      const Record &R = *Groups[i];
93226586Sdim
94226586Sdim      // Start a single option entry.
95226586Sdim      OS << "OPTION(";
96226586Sdim
97226586Sdim      // The option string.
98226586Sdim      OS << '"' << R.getValueAsString("Name") << '"';
99226586Sdim
100226586Sdim      // The option identifier name.
101226586Sdim      OS  << ", "<< getOptionName(R);
102226586Sdim
103226586Sdim      // The option kind.
104226586Sdim      OS << ", Group";
105226586Sdim
106226586Sdim      // The containing option group (if any).
107226586Sdim      OS << ", ";
108226586Sdim      if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
109226586Sdim        OS << getOptionName(*DI->getDef());
110226586Sdim      else
111226586Sdim        OS << "INVALID";
112226586Sdim
113226586Sdim      // The other option arguments (unused for groups).
114226586Sdim      OS << ", INVALID, 0, 0";
115226586Sdim
116226586Sdim      // The option help text.
117226586Sdim      if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
118226586Sdim        OS << ",\n";
119226586Sdim        OS << "       ";
120226586Sdim        write_cstring(OS, R.getValueAsString("HelpText"));
121226586Sdim      } else
122226586Sdim        OS << ", 0";
123226586Sdim
124226586Sdim      // The option meta-variable name (unused).
125226586Sdim      OS << ", 0)\n";
126226586Sdim    }
127226586Sdim    OS << "\n";
128226586Sdim
129226586Sdim    OS << "//////////\n";
130226586Sdim    OS << "// Options\n\n";
131226586Sdim    for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
132226586Sdim      const Record &R = *Opts[i];
133226586Sdim
134226586Sdim      // Start a single option entry.
135226586Sdim      OS << "OPTION(";
136226586Sdim
137226586Sdim      // The option string.
138226586Sdim      write_cstring(OS, R.getValueAsString("Name"));
139226586Sdim
140226586Sdim      // The option identifier name.
141226586Sdim      OS  << ", "<< getOptionName(R);
142226586Sdim
143226586Sdim      // The option kind.
144226586Sdim      OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
145226586Sdim
146226586Sdim      // The containing option group (if any).
147226586Sdim      OS << ", ";
148226586Sdim      if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Group")))
149226586Sdim        OS << getOptionName(*DI->getDef());
150226586Sdim      else
151226586Sdim        OS << "INVALID";
152226586Sdim
153226586Sdim      // The option alias (if any).
154226586Sdim      OS << ", ";
155226586Sdim      if (const DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("Alias")))
156226586Sdim        OS << getOptionName(*DI->getDef());
157226586Sdim      else
158226586Sdim        OS << "INVALID";
159226586Sdim
160226586Sdim      // The option flags.
161226586Sdim      const ListInit *LI = R.getValueAsListInit("Flags");
162226586Sdim      if (LI->empty()) {
163226586Sdim        OS << ", 0";
164226586Sdim      } else {
165226586Sdim        OS << ", ";
166226586Sdim        for (unsigned i = 0, e = LI->size(); i != e; ++i) {
167226586Sdim          if (i)
168226586Sdim            OS << " | ";
169226586Sdim          OS << dynamic_cast<DefInit*>(LI->getElement(i))->getDef()->getName();
170226586Sdim        }
171226586Sdim      }
172226586Sdim
173226586Sdim      // The option parameter field.
174226586Sdim      OS << ", " << R.getValueAsInt("NumArgs");
175226586Sdim
176226586Sdim      // The option help text.
177226586Sdim      if (!dynamic_cast<UnsetInit*>(R.getValueInit("HelpText"))) {
178226586Sdim        OS << ",\n";
179226586Sdim        OS << "       ";
180226586Sdim        write_cstring(OS, R.getValueAsString("HelpText"));
181226586Sdim      } else
182226586Sdim        OS << ", 0";
183226586Sdim
184226586Sdim      // The option meta-variable name.
185226586Sdim      OS << ", ";
186226586Sdim      if (!dynamic_cast<UnsetInit*>(R.getValueInit("MetaVarName")))
187226586Sdim        write_cstring(OS, R.getValueAsString("MetaVarName"));
188226586Sdim      else
189226586Sdim        OS << "0";
190226586Sdim
191226586Sdim      OS << ")\n";
192226586Sdim    }
193226586Sdim  }
194226586Sdim}
195