#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/Streams.h"
-
#include <algorithm>
#include <cassert>
#include <functional>
}
// checkNumberOfArguments - Ensure that the number of args in d is
-// less than or equal to min_arguments, otherwise throw an exception.
+// greater than or equal to min_arguments, otherwise throw an exception.
void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
- if (d->getNumArgs() < min_arguments)
- throw "Property " + d->getOperator()->getAsString()
- + " has too few arguments!";
+ if (!d || d->getNumArgs() < min_arguments)
+ throw d->getOperator()->getAsString() + ": too few arguments!";
}
// isDagEmpty - is this DAG marked with an empty marker?
return ret;
}
+/// oneOf - Does the input string contain this character?
+bool oneOf(const char* lst, char c) {
+ while (*lst) {
+ if (*lst++ == c)
+ return true;
+ }
+ return false;
+}
+
+template <class I, class S>
+void checkedIncrement(I& P, I E, S ErrorString) {
+ ++P;
+ if (P == E)
+ throw ErrorString;
+}
+
//===----------------------------------------------------------------------===//
/// Back-end specific code
/// OptionType - One of six different option types. See the
/// documentation for detailed description of differences.
-/// Extern* options are those that are defined in some other plugin.
namespace OptionType {
+
enum OptionType { Alias, Switch, Parameter, ParameterList,
- Prefix, PrefixList,
- ExternSwitch, ExternParameter, ExternList };
+ Prefix, PrefixList};
-bool IsList (OptionType t) {
- return (t == ParameterList || t == PrefixList || t == ExternList);
-}
+ bool IsList (OptionType t) {
+ return (t == ParameterList || t == PrefixList);
+ }
-bool IsSwitch (OptionType t) {
- return (t == Switch || t == ExternSwitch);
-}
+ bool IsSwitch (OptionType t) {
+ return (t == Switch);
+ }
-bool IsParameter (OptionType t) {
- return (t == Parameter || t == Prefix || t == ExternParameter);
-}
+ bool IsParameter (OptionType t) {
+ return (t == Parameter || t == Prefix);
+ }
}
return OptionType::Prefix;
else if (T == "prefix_list_option")
return OptionType::PrefixList;
- else if (T == "extern_switch")
- return OptionType::ExternSwitch;
- else if (T == "extern_parameter")
- return OptionType::ExternParameter;
- else if (T == "extern_list")
- return OptionType::ExternList;
else
throw "Unknown option type: " + T + '!';
}
namespace OptionDescriptionFlags {
enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
- ReallyHidden = 0x4 };
+ ReallyHidden = 0x4, Extern = 0x8,
+ OneOrMore = 0x10, ZeroOrOne = 0x20 };
}
/// OptionDescription - Represents data contained in a single
std::string Name;
unsigned Flags;
std::string Help;
+ unsigned MultiVal;
+ Init* InitVal;
OptionDescription(OptionType::OptionType t = OptionType::Switch,
const std::string& n = "",
const std::string& h = DefaultHelpString)
- : Type(t), Name(n), Flags(0x0), Help(h)
+ : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0)
{}
/// GenTypeDeclaration - Returns the C++ variable type of this
// Misc convenient getters/setters.
bool isAlias() const;
+
+ bool isMultiVal() const;
+
bool isExtern() const;
+ void setExtern();
bool isRequired() const;
void setRequired();
+ bool isOneOrMore() const;
+ void setOneOrMore();
+
+ bool isZeroOrOne() const;
+ void setZeroOrOne();
+
bool isHidden() const;
void setHidden();
bool isReallyHidden() const;
void setReallyHidden();
+
+ bool isParameter() const
+ { return OptionType::IsParameter(this->Type); }
+
+ bool isSwitch() const
+ { return OptionType::IsSwitch(this->Type); }
+
+ bool isList() const
+ { return OptionType::IsList(this->Type); }
+
};
void OptionDescription::Merge (const OptionDescription& other)
if (Help == other.Help || Help == DefaultHelpString)
Help = other.Help;
else if (other.Help != DefaultHelpString) {
- llvm::cerr << "Warning: several different help strings"
+ llvm::errs() << "Warning: several different help strings"
" defined for option " + Name + "\n";
}
return Type == OptionType::Alias;
}
+bool OptionDescription::isMultiVal() const {
+ return MultiVal > 1;
+}
+
bool OptionDescription::isExtern() const {
- return (Type == OptionType::ExternList || Type == OptionType::ExternParameter
- || Type == OptionType::ExternSwitch);
+ return Flags & OptionDescriptionFlags::Extern;
+}
+void OptionDescription::setExtern() {
+ Flags |= OptionDescriptionFlags::Extern;
}
bool OptionDescription::isRequired() const {
Flags |= OptionDescriptionFlags::Required;
}
+bool OptionDescription::isOneOrMore() const {
+ return Flags & OptionDescriptionFlags::OneOrMore;
+}
+void OptionDescription::setOneOrMore() {
+ Flags |= OptionDescriptionFlags::OneOrMore;
+}
+
+bool OptionDescription::isZeroOrOne() const {
+ return Flags & OptionDescriptionFlags::ZeroOrOne;
+}
+void OptionDescription::setZeroOrOne() {
+ Flags |= OptionDescriptionFlags::ZeroOrOne;
+}
+
bool OptionDescription::isHidden() const {
return Flags & OptionDescriptionFlags::Hidden;
}
switch (Type) {
case OptionType::Alias:
return "cl::alias";
- case OptionType::ExternList:
case OptionType::PrefixList:
case OptionType::ParameterList:
return "cl::list<std::string>";
case OptionType::Switch:
- case OptionType::ExternSwitch:
return "cl::opt<bool>";
- case OptionType::ExternParameter:
case OptionType::Parameter:
case OptionType::Prefix:
default:
return "AutoGeneratedAlias_" + EscapedName;
case OptionType::PrefixList:
case OptionType::ParameterList:
- case OptionType::ExternList:
return "AutoGeneratedList_" + EscapedName;
- case OptionType::ExternSwitch:
case OptionType::Switch:
return "AutoGeneratedSwitch_" + EscapedName;
- case OptionType::ExternParameter:
case OptionType::Prefix:
case OptionType::Parameter:
default:
: HandlerTable<CollectOptionProperties>(this), optDesc_(OD)
{
if (!staticMembersInitialized_) {
+ AddHandler("extern", &CollectOptionProperties::onExtern);
AddHandler("help", &CollectOptionProperties::onHelp);
AddHandler("hidden", &CollectOptionProperties::onHidden);
+ AddHandler("init", &CollectOptionProperties::onInit);
+ AddHandler("multi_val", &CollectOptionProperties::onMultiVal);
+ AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore);
AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden);
AddHandler("required", &CollectOptionProperties::onRequired);
+ AddHandler("zero_or_one", &CollectOptionProperties::onZeroOrOne);
staticMembersInitialized_ = true;
}
/// Option property handlers --
/// Methods that handle option properties such as (help) or (hidden).
+ void onExtern (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ optDesc_.setExtern();
+ }
+
void onHelp (const DagInit* d) {
checkNumberOfArguments(d, 1);
- const std::string& help_message = InitPtrToString(d->getArg(0));
- optDesc_.Help = help_message;
+ optDesc_.Help = InitPtrToString(d->getArg(0));
}
void onHidden (const DagInit* d) {
checkNumberOfArguments(d, 0);
- checkToolProps(d);
optDesc_.setHidden();
}
void onReallyHidden (const DagInit* d) {
checkNumberOfArguments(d, 0);
- checkToolProps(d);
optDesc_.setReallyHidden();
}
void onRequired (const DagInit* d) {
checkNumberOfArguments(d, 0);
- checkToolProps(d);
+ if (optDesc_.isOneOrMore())
+ throw std::string("An option can't have both (required) "
+ "and (one_or_more) properties!");
optDesc_.setRequired();
}
- // Helper functions
+ void onInit (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ Init* i = d->getArg(0);
+ const std::string& str = i->getAsString();
+
+ bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i);
+ correct |= (optDesc_.isSwitch() && (str == "true" || str == "false"));
+
+ if (!correct)
+ throw std::string("Incorrect usage of the 'init' option property!");
- /// checkToolProps - Throw an error if toolProps_ == 0.
- void checkToolProps(const DagInit* d) {
- if (!d)
- throw "Option property " + d->getOperator()->getAsString()
- + " can't be used in this context";
+ optDesc_.InitVal = i;
+ }
+
+ void onOneOrMore (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ if (optDesc_.isRequired() || optDesc_.isZeroOrOne())
+ throw std::string("Only one of (required), (zero_or_one) or "
+ "(one_or_more) properties is allowed!");
+ if (!OptionType::IsList(optDesc_.Type))
+ llvm::errs() << "Warning: specifying the 'one_or_more' property "
+ "on a non-list option will have no effect.\n";
+ optDesc_.setOneOrMore();
+ }
+
+ void onZeroOrOne (const DagInit* d) {
+ checkNumberOfArguments(d, 0);
+ if (optDesc_.isRequired() || optDesc_.isOneOrMore())
+ throw std::string("Only one of (required), (zero_or_one) or "
+ "(one_or_more) properties is allowed!");
+ if (!OptionType::IsList(optDesc_.Type))
+ llvm::errs() << "Warning: specifying the 'zero_or_one' property"
+ "on a non-list option will have no effect.\n";
+ optDesc_.setZeroOrOne();
+ }
+
+ void onMultiVal (const DagInit* d) {
+ checkNumberOfArguments(d, 1);
+ int val = InitPtrToInt(d->getArg(0));
+ if (val < 2)
+ throw std::string("Error in the 'multi_val' property: "
+ "the value must be greater than 1!");
+ if (!OptionType::IsList(optDesc_.Type))
+ throw std::string("The multi_val property is valid only "
+ "on list options!");
+ optDesc_.MultiVal = val;
}
};
void onActions (const DagInit* d) {
checkNumberOfArguments(d, 1);
- toolDesc_.Actions = d->getArg(0);
+ Init* Case = d->getArg(0);
+ if (typeid(*Case) != typeid(DagInit) ||
+ static_cast<DagInit*>(Case)->getOperator()->getAsString() != "case")
+ throw
+ std::string("The argument to (actions) should be a 'case' construct!");
+ toolDesc_.Actions = Case;
}
void onCmdLine (const DagInit* d) {
};
-
/// CollectToolDescriptions - Gather information about tool properties
/// from the parsed TableGen data (basically a wrapper for the
/// CollectToolProperties function object).
E = EdgeVector.end(); B != E; ++B) {
const Record* Edge = *B;
- const std::string& A = Edge->getValueAsString("a");
- const std::string& B = Edge->getValueAsString("b");
+ const std::string& NodeA = Edge->getValueAsString("a");
+ const std::string& NodeB = Edge->getValueAsString("b");
- if (A != "root")
- ToolsInGraph.insert(A);
- ToolsInGraph.insert(B);
+ if (NodeA != "root")
+ ToolsInGraph.insert(NodeA);
+ ToolsInGraph.insert(NodeB);
}
// Filter ToolPropertiesList.
for (RecordVector::const_iterator B = EdgeVector.begin(),
E = EdgeVector.end(); B != E; ++B) {
const Record* Edge = *B;
- const std::string& A = Edge->getValueAsString("a");
- const std::string& B = Edge->getValueAsString("b");
- StringMap<std::string>::iterator IA = ToolToOutLang.find(A);
- StringMap<StringSet<> >::iterator IB = ToolToInLang.find(B);
+ const std::string& NodeA = Edge->getValueAsString("a");
+ const std::string& NodeB = Edge->getValueAsString("b");
+ StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
+ StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
- if (A != "root") {
+ if (NodeA != "root") {
if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
- throw "Edge " + A + "->" + B
+ throw "Edge " + NodeA + "->" + NodeB
+ ": output->input language mismatch";
}
- if (B == "root")
+ if (NodeB == "root")
throw std::string("Edges back to the root are not allowed!");
}
}
if (ActionName == "forward" || ActionName == "forward_as" ||
ActionName == "unpack_values" || ActionName == "switch_on" ||
ActionName == "parameter_equals" || ActionName == "element_in_list" ||
- ActionName == "not_empty") {
+ ActionName == "not_empty" || ActionName == "empty") {
checkNumberOfArguments(&Stmt, 1);
const std::string& Name = InitPtrToString(Stmt.getArg(0));
OptionNames_.insert(Name);
const OptionDescription& Val = B->second;
if (!nonSuperfluousOptions.count(Val.Name)
&& Val.Type != OptionType::Alias)
- llvm::cerr << "Warning: option '-" << Val.Name << "' has no effect! "
+ llvm::errs() << "Warning: option '-" << Val.Name << "' has no effect! "
"Probable cause: this option is specified only in the OptionList.\n";
}
}
bool EmitCaseTest1Arg(const std::string& TestName,
const DagInit& d,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
checkNumberOfArguments(&d, 1);
const std::string& OptName = InitPtrToString(d.getArg(0));
+
if (TestName == "switch_on") {
const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
- if (!OptionType::IsSwitch(OptDesc.Type))
+ if (!OptDesc.isSwitch())
throw OptName + ": incorrect option type - should be a switch!";
O << OptDesc.GenVariableName();
return true;
// TODO: make this work with Edge::Weight (if possible).
O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"';
return true;
- } else if (TestName == "not_empty") {
+ } else if (TestName == "not_empty" || TestName == "empty") {
+ const char* Test = (TestName == "empty") ? "" : "!";
+
if (OptName == "o") {
- O << "!OutputFilename.empty()";
+ O << Test << "OutputFilename.empty()";
return true;
}
else {
const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
- if (OptionType::IsSwitch(OptDesc.Type))
+ if (OptDesc.isSwitch())
throw OptName
+ ": incorrect option type - should be a list or parameter!";
- O << '!' << OptDesc.GenVariableName() << ".empty()";
+ O << Test << OptDesc.GenVariableName() << ".empty()";
return true;
}
}
const DagInit& d,
const char* IndentLevel,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
checkNumberOfArguments(&d, 2);
const std::string& OptName = InitPtrToString(d.getArg(0));
const std::string& OptArg = InitPtrToString(d.getArg(1));
const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
if (TestName == "parameter_equals") {
- if (!OptionType::IsParameter(OptDesc.Type))
+ if (!OptDesc.isParameter())
throw OptName + ": incorrect option type - should be a parameter!";
O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
return true;
}
else if (TestName == "element_in_list") {
- if (!OptionType::IsList(OptDesc.Type))
+ if (!OptDesc.isList())
throw OptName + ": incorrect option type - should be a list!";
const std::string& VarName = OptDesc.GenVariableName();
O << "std::find(" << VarName << ".begin(),\n"
// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
void EmitCaseTest(const DagInit& d, const char* IndentLevel,
const OptionDescriptions& OptDescs,
- std::ostream& O);
+ raw_ostream& O);
/// EmitLogicalOperationTest - Helper function used by
/// EmitCaseConstructHandler.
void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
const char* IndentLevel,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
O << '(';
for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
void EmitCaseTest(const DagInit& d, const char* IndentLevel,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
const std::string& TestName = d.getOperator()->getAsString();
if (TestName == "and")
// Emit code that handles the 'case' construct.
// Takes a function object that should emit code for every case clause.
// Callback's type is
-// void F(Init* Statement, const char* IndentLevel, std::ostream& O).
+// void F(Init* Statement, const char* IndentLevel, raw_ostream& O).
template <typename F>
void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel,
F Callback, bool EmitElseIf,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
const DagInit* d = &InitPtrToDag(Dag);
if (d->getOperator()->getAsString() != "case")
throw std::string("EmitCaseConstructHandler should be invoked"
}
}
+/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to
+/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] .
+/// Helper function used by EmitCmdLineVecFill and.
+void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
+ const char* Delimiters = " \t\n\v\f\r";
+ enum TokenizerState
+ { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
+ cur_st = Normal;
+
+ if (CmdLine.empty())
+ return;
+ Out.push_back("");
+
+ std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
+ E = CmdLine.size();
+
+ for (; B != E; ++B) {
+ char cur_ch = CmdLine[B];
+
+ switch (cur_st) {
+ case Normal:
+ if (cur_ch == '$') {
+ cur_st = SpecialCommand;
+ break;
+ }
+ if (oneOf(Delimiters, cur_ch)) {
+ // Skip whitespace
+ B = CmdLine.find_first_not_of(Delimiters, B);
+ if (B == std::string::npos) {
+ B = E-1;
+ continue;
+ }
+ --B;
+ Out.push_back("");
+ continue;
+ }
+ break;
+
+
+ case SpecialCommand:
+ if (oneOf(Delimiters, cur_ch)) {
+ cur_st = Normal;
+ Out.push_back("");
+ continue;
+ }
+ if (cur_ch == '(') {
+ Out.push_back("");
+ cur_st = InsideSpecialCommand;
+ continue;
+ }
+ break;
+
+ case InsideSpecialCommand:
+ if (oneOf(Delimiters, cur_ch)) {
+ continue;
+ }
+ if (cur_ch == '\'') {
+ cur_st = InsideQuotationMarks;
+ Out.push_back("");
+ continue;
+ }
+ if (cur_ch == ')') {
+ cur_st = Normal;
+ Out.push_back("");
+ }
+ if (cur_ch == ',') {
+ continue;
+ }
+
+ break;
+
+ case InsideQuotationMarks:
+ if (cur_ch == '\'') {
+ cur_st = InsideSpecialCommand;
+ continue;
+ }
+ break;
+ }
+
+ Out.back().push_back(cur_ch);
+ }
+}
+
/// SubstituteSpecialCommands - Perform string substitution for $CALL
/// and $ENV. Helper function used by EmitCmdLineVecFill().
-std::string SubstituteSpecialCommands(const std::string& cmd) {
- size_t cparen = cmd.find(")");
- std::string ret;
+StrVector::const_iterator SubstituteSpecialCommands
+(StrVector::const_iterator Pos, StrVector::const_iterator End, raw_ostream& O)
+{
+
+ const std::string& cmd = *Pos;
- if (cmd.find("$CALL(") == 0) {
- if (cmd.size() == 6)
+ if (cmd == "$CALL") {
+ checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
+ const std::string& CmdName = *Pos;
+
+ if (CmdName == ")")
throw std::string("$CALL invocation: empty argument list!");
- ret += "hooks::";
- ret += std::string(cmd.begin() + 6, cmd.begin() + cparen);
- ret += "()";
+ O << "hooks::";
+ O << CmdName << "(";
+
+
+ bool firstIteration = true;
+ while (true) {
+ checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
+ const std::string& Arg = *Pos;
+ assert(Arg.size() != 0);
+
+ if (Arg[0] == ')')
+ break;
+
+ if (firstIteration)
+ firstIteration = false;
+ else
+ O << ", ";
+
+ O << '"' << Arg << '"';
+ }
+
+ O << ')';
+
}
- else if (cmd.find("$ENV(") == 0) {
- if (cmd.size() == 5)
- throw std::string("$ENV invocation: empty argument list!");
+ else if (cmd == "$ENV") {
+ checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
+ const std::string& EnvName = *Pos;
+
+ if (EnvName == ")")
+ throw "$ENV invocation: empty argument list!";
+
+ O << "checkCString(std::getenv(\"";
+ O << EnvName;
+ O << "\"))";
- ret += "checkCString(std::getenv(\"";
- ret += std::string(cmd.begin() + 5, cmd.begin() + cparen);
- ret += "\"))";
+ checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
}
else {
throw "Unknown special command: " + cmd;
}
- if (cmd.begin() + cparen + 1 != cmd.end()) {
- ret += " + std::string(\"";
- ret += (cmd.c_str() + cparen + 1);
- ret += "\")";
- }
+ const std::string& Leftover = *Pos;
+ assert(Leftover.at(0) == ')');
+ if (Leftover.size() != 1)
+ O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
- return ret;
+ return Pos;
}
/// EmitCmdLineVecFill - Emit code that fills in the command line
/// vector. Helper function used by EmitGenerateActionMethod().
void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
bool IsJoin, const char* IndentLevel,
- std::ostream& O) {
+ raw_ostream& O) {
StrVector StrVec;
- SplitString(InitPtrToString(CmdLine), StrVec);
+ TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
+
if (StrVec.empty())
- throw "Tool " + ToolName + " has empty command line!";
+ throw "Tool '" + ToolName + "' has empty command line!";
+
+ StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
+
+ // If there is a hook invocation on the place of the first command, skip it.
+ assert(!StrVec[0].empty());
+ if (StrVec[0][0] == '$') {
+ while (I != E && (*I)[0] != ')' )
+ ++I;
- StrVector::const_iterator I = StrVec.begin();
- ++I;
- for (StrVector::const_iterator E = StrVec.end(); I != E; ++I) {
+ // Skip the ')' symbol.
+ ++I;
+ }
+ else {
+ ++I;
+ }
+
+ for (; I != E; ++I) {
const std::string& cmd = *I;
+ assert(!cmd.empty());
O << IndentLevel;
if (cmd.at(0) == '$') {
if (cmd == "$INFILE") {
O << "for (PathVector::const_iterator B = inFiles.begin()"
<< ", E = inFiles.end();\n"
<< IndentLevel << "B != E; ++B)\n"
- << IndentLevel << Indent1 << "vec.push_back(B->toString());\n";
+ << IndentLevel << Indent1 << "vec.push_back(B->str());\n";
else
- O << "vec.push_back(inFile.toString());\n";
+ O << "vec.push_back(inFile.str());\n";
}
else if (cmd == "$OUTFILE") {
O << "vec.push_back(out_file);\n";
}
else {
- O << "vec.push_back(" << SubstituteSpecialCommands(cmd);
+ O << "vec.push_back(";
+ I = SubstituteSpecialCommands(I, E, O);
O << ");\n";
}
}
O << "vec.push_back(\"" << cmd << "\");\n";
}
}
- O << IndentLevel << "cmd = "
- << ((StrVec[0][0] == '$') ? SubstituteSpecialCommands(StrVec[0])
- : "\"" + StrVec[0] + "\"")
- << ";\n";
+ O << IndentLevel << "cmd = ";
+
+ if (StrVec[0][0] == '$')
+ SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O);
+ else
+ O << '"' << StrVec[0] << '"';
+ O << ";\n";
}
/// EmitCmdLineVecFillCallback - A function object wrapper around
: IsJoin(J), ToolName(TN) {}
void operator()(const Init* Statement, const char* IndentLevel,
- std::ostream& O) const
+ raw_ostream& O) const
{
EmitCmdLineVecFill(Statement, ToolName, IsJoin,
IndentLevel, O);
void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
const char* Indent,
const std::string& NewName,
- std::ostream& O) {
+ raw_ostream& O) {
const std::string& Name = NewName.empty()
? ("-" + D.Name)
: NewName;
switch (D.Type) {
case OptionType::Switch:
- case OptionType::ExternSwitch:
O << Indent << "vec.push_back(\"" << Name << "\");\n";
break;
case OptionType::Parameter:
- case OptionType::ExternParameter:
O << Indent << "vec.push_back(\"" << Name << "\");\n";
O << Indent << "vec.push_back(" << D.GenVariableName() << ");\n";
break;
case OptionType::PrefixList:
O << Indent << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n"
- << Indent << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n"
+ << Indent << "E = " << D.GenVariableName() << ".end(); B != E;) {\n"
<< Indent << Indent1 << "vec.push_back(\"" << Name << "\" + "
- << "*B);\n";
+ << "*B);\n"
+ << Indent << Indent1 << "++B;\n";
+
+ for (int i = 1, j = D.MultiVal; i < j; ++i) {
+ O << Indent << Indent1 << "vec.push_back(*B);\n"
+ << Indent << Indent1 << "++B;\n";
+ }
+
+ O << Indent << "}\n";
break;
case OptionType::ParameterList:
- case OptionType::ExternList:
O << Indent << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n"
<< Indent << "E = " << D.GenVariableName()
- << ".end() ; B != E; ++B) {\n"
- << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n"
- << Indent << Indent1 << "vec.push_back(*B);\n"
- << Indent << "}\n";
+ << ".end() ; B != E;) {\n"
+ << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n";
+
+ for (int i = 0, j = D.MultiVal; i < j; ++i) {
+ O << Indent << Indent1 << "vec.push_back(*B);\n"
+ << Indent << Indent1 << "++B;\n";
+ }
+
+ O << Indent << "}\n";
break;
case OptionType::Alias:
default:
const OptionDescriptions& OptDescs;
void processActionDag(const Init* Statement, const char* IndentLevel,
- std::ostream& O) const
+ raw_ostream& O) const
{
const DagInit& Dag = InitPtrToDag(Statement);
const std::string& ActionName = Dag.getOperator()->getAsString();
if (ActionName == "append_cmd") {
checkNumberOfArguments(&Dag, 1);
const std::string& Cmd = InitPtrToString(Dag.getArg(0));
- O << IndentLevel << "vec.push_back(\"" << Cmd << "\");\n";
+ StrVector Out;
+ llvm::SplitString(Cmd, Out);
+
+ for (StrVector::const_iterator B = Out.begin(), E = Out.end();
+ B != E; ++B)
+ O << IndentLevel << "vec.push_back(\"" << *B << "\");\n";
+ }
+ else if (ActionName == "error") {
+ O << IndentLevel << "throw std::runtime_error(\"" <<
+ (Dag.getNumArgs() >= 1 ? InitPtrToString(Dag.getArg(0))
+ : "Unknown error!")
+ << "\");\n";
}
else if (ActionName == "forward") {
checkNumberOfArguments(&Dag, 1);
else if (ActionName == "forward_as") {
checkNumberOfArguments(&Dag, 2);
const std::string& Name = InitPtrToString(Dag.getArg(0));
- const std::string& NewName = InitPtrToString(Dag.getArg(0));
+ const std::string& NewName = InitPtrToString(Dag.getArg(1));
EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
IndentLevel, NewName, O);
}
const std::string& Name = InitPtrToString(Dag.getArg(0));
const OptionDescription& D = OptDescs.FindOption(Name);
- if (OptionType::IsList(D.Type)) {
+ if (D.isMultiVal())
+ throw std::string("Can't use unpack_values with multi-valued options!");
+
+ if (D.isList()) {
O << IndentLevel << "for (" << D.GenTypeDeclaration()
<< "::iterator B = " << D.GenVariableName() << ".begin(),\n"
<< IndentLevel << "E = " << D.GenVariableName()
<< ".end(); B != E; ++B)\n"
<< IndentLevel << Indent1 << "llvm::SplitString(*B, vec, \",\");\n";
}
- else if (OptionType::IsParameter(D.Type)){
+ else if (D.isParameter()){
O << Indent3 << "llvm::SplitString("
<< D.GenVariableName() << ", vec, \",\");\n";
}
: OptDescs(OD) {}
void operator()(const Init* Statement, const char* IndentLevel,
- std::ostream& O) const
+ raw_ostream& O) const
{
if (typeid(*Statement) == typeid(ListInit)) {
const ListInit& DagList = *static_cast<const ListInit*>(Statement);
// Tool::GenerateAction() method.
void EmitGenerateActionMethod (const ToolDescription& D,
const OptionDescriptions& OptDescs,
- bool IsJoin, std::ostream& O) {
+ bool IsJoin, raw_ostream& O) {
if (IsJoin)
O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
else
O << '\n' << Indent2
<< "out_file = OutFilename(" << (IsJoin ? "sys::Path(),\n" : "inFile,\n")
- << Indent3 << "TempDir, stop_compilation, output_suffix).toString();\n\n";
+ << Indent3 << "TempDir, stop_compilation, output_suffix).str();\n\n";
// cmd_line is either a string or a 'case' construct.
if (!D.CmdLine)
/// a given Tool class.
void EmitGenerateActionMethods (const ToolDescription& ToolDesc,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
if (!ToolDesc.isJoin())
O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
<< Indent2 << "bool HasChildren,\n"
/// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
/// methods for a given Tool class.
-void EmitInOutLanguageMethods (const ToolDescription& D, std::ostream& O) {
+void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
O << Indent1 << "const char** InputLanguages() const {\n"
<< Indent2 << "return InputLanguages_;\n"
<< Indent1 << "}\n\n";
}
/// EmitNameMethod - Emit the Name() method for a given Tool class.
-void EmitNameMethod (const ToolDescription& D, std::ostream& O) {
+void EmitNameMethod (const ToolDescription& D, raw_ostream& O) {
O << Indent1 << "const char* Name() const {\n"
<< Indent2 << "return \"" << D.Name << "\";\n"
<< Indent1 << "}\n\n";
/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
/// class.
-void EmitIsJoinMethod (const ToolDescription& D, std::ostream& O) {
+void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) {
O << Indent1 << "bool IsJoin() const {\n";
if (D.isJoin())
O << Indent2 << "return true;\n";
/// EmitStaticMemberDefinitions - Emit static member definitions for a
/// given Tool class.
-void EmitStaticMemberDefinitions(const ToolDescription& D, std::ostream& O) {
+void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) {
if (D.InLanguage.empty())
throw "Tool " + D.Name + " has no 'in_language' property!";
/// EmitToolClassDefinition - Emit a Tool class definition.
void EmitToolClassDefinition (const ToolDescription& D,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
if (D.Name == "root")
return;
}
-/// EmitOptionDefintions - Iterate over a list of option descriptions
+/// EmitOptionDefinitions - Iterate over a list of option descriptions
/// and emit registration code.
-void EmitOptionDefintions (const OptionDescriptions& descs,
- bool HasSink, bool HasExterns,
- std::ostream& O)
+void EmitOptionDefinitions (const OptionDescriptions& descs,
+ bool HasSink, bool HasExterns,
+ raw_ostream& O)
{
std::vector<OptionDescription> Aliases;
continue;
}
- O << "(\"" << val.Name << '\"';
+ O << "(\"" << val.Name << "\"\n";
if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
O << ", cl::Prefix";
if (val.isRequired()) {
- switch (val.Type) {
- case OptionType::PrefixList:
- case OptionType::ParameterList:
+ if (val.isList() && !val.isMultiVal())
O << ", cl::OneOrMore";
- break;
- default:
+ else
O << ", cl::Required";
- }
+ }
+ else if (val.isOneOrMore() && val.isList()) {
+ O << ", cl::OneOrMore";
+ }
+ else if (val.isZeroOrOne() && val.isList()) {
+ O << ", cl::ZeroOrOne";
}
- if (val.isReallyHidden() || val.isHidden()) {
- if (val.isRequired())
- O << " |";
- else
- O << ",";
- if (val.isReallyHidden())
- O << " cl::ReallyHidden";
- else
- O << " cl::Hidden";
+ if (val.isReallyHidden()) {
+ O << ", cl::ReallyHidden";
+ }
+ else if (val.isHidden()) {
+ O << ", cl::Hidden";
+ }
+
+ if (val.MultiVal > 1)
+ O << ", cl::multi_val(" << val.MultiVal << ')';
+
+ if (val.InitVal) {
+ const std::string& str = val.InitVal->getAsString();
+ O << ", cl::init(" << str << ')';
}
if (!val.Help.empty())
O << ", cl::desc(\"" << val.Help << "\")";
- O << ");\n";
+ O << ");\n\n";
}
// Emit the aliases (they should go after all the 'proper' options).
}
/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
-void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
+void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
{
// Generate code
- O << "namespace {\n\n";
O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
// Get the relevant field out of RecordKeeper
}
}
- O << "}\n\n}\n\n";
+ O << "}\n\n";
}
/// IncDecWeight - Helper function passed to EmitCaseConstructHandler()
/// by EmitEdgeClass().
void IncDecWeight (const Init* i, const char* IndentLevel,
- std::ostream& O) {
+ raw_ostream& O) {
const DagInit& d = InitPtrToDag(i);
const std::string& OpName = d.getOperator()->getAsString();
- if (OpName == "inc_weight")
+ if (OpName == "inc_weight") {
O << IndentLevel << "ret += ";
- else if (OpName == "dec_weight")
+ }
+ else if (OpName == "dec_weight") {
O << IndentLevel << "ret -= ";
+ }
+ else if (OpName == "error") {
+ O << IndentLevel << "throw std::runtime_error(\"" <<
+ (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0))
+ : "Unknown error!")
+ << "\");\n";
+ return;
+ }
+
else
- throw "Unknown operator in edge properties list: " + OpName + '!';
+ throw "Unknown operator in edge properties list: " + OpName + '!' +
+ "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
if (d.getNumArgs() > 0)
O << InitPtrToInt(d.getArg(0)) << ";\n";
/// EmitEdgeClass - Emit a single Edge# class.
void EmitEdgeClass (unsigned N, const std::string& Target,
DagInit* Case, const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
// Class constructor.
O << "class Edge" << N << ": public Edge {\n"
/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
void EmitEdgeClasses (const RecordVector& EdgeVector,
const OptionDescriptions& OptDescs,
- std::ostream& O) {
+ raw_ostream& O) {
int i = 0;
- for (RecordVector::const_iterator Beg = EdgeVector.begin(),
- E = EdgeVector.end(); Beg != E; ++Beg) {
- const Record* Edge = *Beg;
- const std::string& B = Edge->getValueAsString("b");
+ for (RecordVector::const_iterator B = EdgeVector.begin(),
+ E = EdgeVector.end(); B != E; ++B) {
+ const Record* Edge = *B;
+ const std::string& NodeB = Edge->getValueAsString("b");
DagInit* Weight = Edge->getValueAsDag("weight");
if (!isDagEmpty(Weight))
- EmitEdgeClass(i, B, Weight, OptDescs, O);
+ EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
++i;
}
}
/// function.
void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
const ToolDescriptions& ToolDescs,
- std::ostream& O)
+ raw_ostream& O)
{
- O << "namespace {\n\n";
O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
// Insert edges.
int i = 0;
- for (RecordVector::const_iterator Beg = EdgeVector.begin(),
- E = EdgeVector.end(); Beg != E; ++Beg) {
- const Record* Edge = *Beg;
- const std::string& A = Edge->getValueAsString("a");
- const std::string& B = Edge->getValueAsString("b");
+ for (RecordVector::const_iterator B = EdgeVector.begin(),
+ E = EdgeVector.end(); B != E; ++B) {
+ const Record* Edge = *B;
+ const std::string& NodeA = Edge->getValueAsString("a");
+ const std::string& NodeB = Edge->getValueAsString("b");
DagInit* Weight = Edge->getValueAsDag("weight");
- O << Indent1 << "G.insertEdge(\"" << A << "\", ";
+ O << Indent1 << "G.insertEdge(\"" << NodeA << "\", ";
if (isDagEmpty(Weight))
- O << "new SimpleEdge(\"" << B << "\")";
+ O << "new SimpleEdge(\"" << NodeB << "\")";
else
O << "new Edge" << i << "()";
++i;
}
- O << "}\n\n}\n\n";
+ O << "}\n\n";
}
/// ExtractHookNames - Extract the hook names from all instances of
/// $CALL(HookName) in the provided command line string. Helper
/// function used by FillInHookNames().
class ExtractHookNames {
- llvm::StringSet<>& HookNames_;
+ llvm::StringMap<unsigned>& HookNames_;
public:
- ExtractHookNames(llvm::StringSet<>& HookNames)
- : HookNames_(HookNames_) {}
+ ExtractHookNames(llvm::StringMap<unsigned>& HookNames)
+ : HookNames_(HookNames) {}
void operator()(const Init* CmdLine) {
StrVector cmds;
- llvm::SplitString(InitPtrToString(CmdLine), cmds);
+ TokenizeCmdline(InitPtrToString(CmdLine), cmds);
for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
B != E; ++B) {
const std::string& cmd = *B;
- if (cmd.find("$CALL(") == 0) {
- if (cmd.size() == 6)
- throw std::string("$CALL invocation: empty argument list!");
- HookNames_.insert(std::string(cmd.begin() + 6,
- cmd.begin() + cmd.find(")")));
+
+ if (cmd == "$CALL") {
+ unsigned NumArgs = 0;
+ checkedIncrement(B, E, "Syntax error in $CALL invocation!");
+ const std::string& HookName = *B;
+
+
+ if (HookName.at(0) == ')')
+ throw "$CALL invoked with no arguments!";
+
+ while (++B != E && B->at(0) != ')') {
+ ++NumArgs;
+ }
+
+ StringMap<unsigned>::const_iterator H = HookNames_.find(HookName);
+
+ if (H != HookNames_.end() && H->second != NumArgs)
+ throw "Overloading of hooks is not allowed. Overloaded hook: "
+ + HookName;
+ else
+ HookNames_[HookName] = NumArgs;
+
}
}
}
/// FillInHookNames - Actually extract the hook names from all command
/// line strings. Helper function used by EmitHookDeclarations().
void FillInHookNames(const ToolDescriptions& ToolDescs,
- llvm::StringSet<>& HookNames)
+ llvm::StringMap<unsigned>& HookNames)
{
// For all command lines:
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
/// EmitHookDeclarations - Parse CmdLine fields of all the tool
/// property records and emit hook function declaration for each
/// instance of $CALL(HookName).
-void EmitHookDeclarations(const ToolDescriptions& ToolDescs, std::ostream& O) {
- llvm::StringSet<> HookNames;
+void EmitHookDeclarations(const ToolDescriptions& ToolDescs, raw_ostream& O) {
+ llvm::StringMap<unsigned> HookNames;
+
FillInHookNames(ToolDescs, HookNames);
if (HookNames.empty())
return;
O << "namespace hooks {\n";
- for (StringSet<>::const_iterator B = HookNames.begin(), E = HookNames.end();
- B != E; ++B)
- O << Indent1 << "std::string " << B->first() << "();\n";
+ for (StringMap<unsigned>::const_iterator B = HookNames.begin(),
+ E = HookNames.end(); B != E; ++B) {
+ O << Indent1 << "std::string " << B->first() << "(";
+ for (unsigned i = 0, j = B->second; i < j; ++i) {
+ O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
+ }
+
+ O <<");\n";
+ }
O << "}\n\n";
}
/// EmitRegisterPlugin - Emit code to register this plugin.
-void EmitRegisterPlugin(int Priority, std::ostream& O) {
- O << "namespace {\n\n"
- << "struct Plugin : public llvmc::BasePlugin {\n\n"
+void EmitRegisterPlugin(int Priority, raw_ostream& O) {
+ O << "struct Plugin : public llvmc::BasePlugin {\n\n"
<< Indent1 << "int Priority() const { return " << Priority << "; }\n\n"
<< Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n"
<< Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n"
<< Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n"
<< "};\n\n"
- << "static llvmc::RegisterPlugin<Plugin> RP;\n\n}\n\n";
+ << "static llvmc::RegisterPlugin<Plugin> RP;\n\n";
}
/// EmitIncludes - Emit necessary #include directives and some
/// additional declarations.
-void EmitIncludes(std::ostream& O) {
+void EmitIncludes(raw_ostream& O) {
O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
+ << "#include \"llvm/CompilerDriver/ForceLinkageMacros.h\"\n"
<< "#include \"llvm/CompilerDriver/Plugin.h\"\n"
<< "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
}
-void EmitPluginCode(const PluginData& Data, std::ostream& O) {
+void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
// Emit file header.
EmitIncludes(O);
// Emit global option registration code.
- EmitOptionDefintions(Data.OptDescs, Data.HasSink, Data.HasExterns, O);
+ EmitOptionDefinitions(Data.OptDescs, Data.HasSink, Data.HasExterns, O);
// Emit hook declarations.
EmitHookDeclarations(Data.ToolDescs, O);
+ O << "namespace {\n\n";
+
// Emit PopulateLanguageMap() function
// (a language map maps from file extensions to language names).
EmitPopulateLanguageMap(Records, O);
// Emit code for plugin registration.
EmitRegisterPlugin(Data.Priority, O);
+ O << "} // End anonymous namespace.\n\n";
+
+ // Force linkage magic.
+ O << "namespace llvmc {\n";
+ O << "LLVMC_FORCE_LINKAGE_DECL(LLVMC_PLUGIN_NAME) {}\n";
+ O << "}\n";
+
// EOF
}
}
/// run - The back-end entry point.
-void LLVMCConfigurationEmitter::run (std::ostream &O) {
+void LLVMCConfigurationEmitter::run (raw_ostream &O) {
try {
PluginData Data;