mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-02 00:36:36 +00:00
First version of a utility internal to llvmc that handles the parsing and
construction of configuration data for compiler front ends. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15727 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2c8ab588d5
commit
2594c9abbf
441
tools/llvmc/ConfigData.cpp
Normal file
441
tools/llvmc/ConfigData.cpp
Normal file
@ -0,0 +1,441 @@
|
||||
//===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Reid Spencer and is distributed under the
|
||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the parsing of configuration files for the LLVM Compiler
|
||||
// Driver (llvmc).
|
||||
//
|
||||
//===------------------------------------------------------------------------===
|
||||
|
||||
#include "ConfigData.h"
|
||||
#include "CompilerDriver.h"
|
||||
#include "Support/StringExtras.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
// This array of strings provides the input for ".ll" files (LLVM Assembly)
|
||||
// to the configuration file parser. This data is just "built-in" to
|
||||
// llvmc so it doesn't have to be read from a configuration file.
|
||||
static const char* LL_Data[] = {
|
||||
"lang.name=LLVM Assembly",
|
||||
"lang.translator.preprocesses=false",
|
||||
"lang.translator.optimizes=No",
|
||||
"lang.translator.groks_dash_O=No",
|
||||
"lang.preprocessor.needed=0",
|
||||
"preprocessor.prog=",
|
||||
"preprocessor.args=",
|
||||
"translator.prog=llvm-as",
|
||||
"translator.args=@in@ -o @out@",
|
||||
"optimizer.prog=opt",
|
||||
"optimizer.args=@in@ -o @out@",
|
||||
"assembler.prog=llc",
|
||||
"assembler.args=@in@ -o @out@",
|
||||
"linker.prog=llvm-link",
|
||||
"linker.args=@in@ -o @out@"
|
||||
};
|
||||
|
||||
// This array of strings provides the input for ".st" files (Stacker).
|
||||
static const char* ST_Data[] = {
|
||||
"lang.name=Stacker",
|
||||
"lang.translator.preprocesses=false",
|
||||
"lang.translator.optimizes=true",
|
||||
"lang.translator.groks_dash_O=0",
|
||||
"lang.preprocessor.needed=0",
|
||||
"preprocessor.prog=cp",
|
||||
"preprocessor.args=@in@ @out@",
|
||||
"translator.prog=stkrc",
|
||||
"translator.args=@in@ -o @out@ -S 2048",
|
||||
"optimizer.prog=opt",
|
||||
"optimizer.args=@in@ -o @out@",
|
||||
"assembler.prog=llc",
|
||||
"assembler.args=@in@ -o @out@",
|
||||
"linker.prog=llvm-link",
|
||||
"linker.args=@in@ -o @out@"
|
||||
};
|
||||
|
||||
class InputProvider {
|
||||
public:
|
||||
virtual bool getLine(std::string& line) = 0;
|
||||
virtual void error(const std::string& msg) = 0;
|
||||
virtual bool errorOccurred() = 0;
|
||||
};
|
||||
|
||||
class StaticInputProvider : public InputProvider {
|
||||
public:
|
||||
StaticInputProvider(const char *data[], size_t count,
|
||||
const std::string& nam) {
|
||||
TheData = data;
|
||||
limit = count;
|
||||
where = 0;
|
||||
name = nam;
|
||||
errCount = 0;
|
||||
}
|
||||
virtual ~StaticInputProvider() {}
|
||||
virtual bool getLine(std::string& line) {
|
||||
if ( where >= limit ) return false;
|
||||
line = TheData[where++];
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void error(const std::string& msg) {
|
||||
std::cerr << name << ":" << where << ": Error: " << msg << "\n";
|
||||
errCount++;
|
||||
}
|
||||
|
||||
virtual bool errorOccurred() { return errCount > 0; };
|
||||
|
||||
private:
|
||||
const char**TheData;
|
||||
size_t limit;
|
||||
size_t where;
|
||||
std::string name;
|
||||
size_t errCount;
|
||||
};
|
||||
|
||||
inline bool recognize(const char*& p, const char*token) {
|
||||
while (*p == *token && *token != '\0')
|
||||
++token, p++;
|
||||
return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
|
||||
}
|
||||
|
||||
inline bool getBoolean(const std::string& value) {
|
||||
switch (value[0]) {
|
||||
case 't':
|
||||
case 'T':
|
||||
case '1':
|
||||
case 'y':
|
||||
case 'Y':
|
||||
return true;
|
||||
default :
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void skipWhitespace( size_t& pos, const std::string& line ) {
|
||||
while (pos < line.size() && (
|
||||
line[pos] == ' ' || // Space
|
||||
line[pos] == '\t' || // Horizontal Tab
|
||||
line[pos] == '\n' || // New Line
|
||||
line[pos] == '\v' || // Vertical Tab
|
||||
line[pos] == '\f' || // Form Feed
|
||||
line[pos] == '\r') // Carriate Return
|
||||
)
|
||||
pos++;
|
||||
}
|
||||
|
||||
inline void parseArgs(CompilerDriver::Action& pat,
|
||||
const std::string& value,
|
||||
InputProvider& provider )
|
||||
{
|
||||
const char* p = value.c_str();
|
||||
const char* argStart = p;
|
||||
while (*p != '\0') {
|
||||
switch (*p) {
|
||||
case ' ':
|
||||
if (argStart != p)
|
||||
pat.args.push_back(std::string(argStart, p-argStart));
|
||||
argStart = ++p;
|
||||
break;
|
||||
case '@' :
|
||||
{
|
||||
if (argStart != p)
|
||||
pat.args.push_back(std::string(argStart,p-argStart));
|
||||
const char* token = ++p;
|
||||
while (*p != '@' && *p != 0)
|
||||
p++;
|
||||
if ( *p != '@' ) {
|
||||
provider.error("Unterminated substitution token");
|
||||
return;
|
||||
} else {
|
||||
p++;
|
||||
bool legal = false;
|
||||
switch (token[0]) {
|
||||
case 'i':
|
||||
if (token[1] == 'n' && token[2] == '@' ) {
|
||||
pat.inputAt = pat.args.size();
|
||||
pat.args.push_back("in");
|
||||
legal = true;
|
||||
argStart = p;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (token[1] == 'u' && token[2] == 't' && token[3] == '@') {
|
||||
pat.outputAt = pat.args.size();
|
||||
pat.args.push_back("out");
|
||||
legal = true;
|
||||
argStart = p;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!legal) {
|
||||
provider.error("Invalid substitution token");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default :
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CompilerDriver::ConfigData*
|
||||
ParseConfigData(InputProvider& provider) {
|
||||
std::string line;
|
||||
CompilerDriver::ConfigData data;
|
||||
while ( provider.getLine(line) ) {
|
||||
// Check line length first
|
||||
size_t lineLen = line.size();
|
||||
if (lineLen > 4096)
|
||||
provider.error("length of input line (" + utostr(lineLen) +
|
||||
") is too long");
|
||||
|
||||
// First, skip whitespace
|
||||
size_t stPos = 0;
|
||||
skipWhitespace(stPos, line);
|
||||
|
||||
// See if there's a hash mark. It and everything after it is
|
||||
// ignored so lets delete that now.
|
||||
size_t hashPos = line.find('#');
|
||||
if (hashPos != std::string::npos)
|
||||
line.erase(hashPos);
|
||||
|
||||
// Make sure we have something left to parse
|
||||
if (line.size() == 0)
|
||||
continue; // ignore full-line comment or whitespace line
|
||||
|
||||
// Find the equals sign
|
||||
size_t eqPos = line.find('=');
|
||||
if (eqPos == std::string::npos)
|
||||
provider.error("Configuration directive is missing an =");
|
||||
|
||||
// extract the item name
|
||||
std::string name(line, stPos, eqPos-stPos);
|
||||
|
||||
// directives without names are illegal
|
||||
if (name.empty())
|
||||
provider.error("Configuration directive name is empty");
|
||||
|
||||
// Skip whitespace in the value
|
||||
size_t valPos = eqPos + 1;
|
||||
skipWhitespace(valPos, line);
|
||||
|
||||
// Skip white space at end of value
|
||||
size_t endPos = line.length() - 1;
|
||||
while (line[endPos] == ' ')
|
||||
endPos--;
|
||||
|
||||
// extract the item value
|
||||
std::string value(line, valPos, endPos-valPos+1);
|
||||
|
||||
// Get the configuration item as a char pointer
|
||||
const char*p = name.c_str();
|
||||
|
||||
// Indicate we haven't found an invalid item yet.
|
||||
bool invalidItem = false;
|
||||
|
||||
// Parse the contents by examining first character and
|
||||
// using the recognize function strategically
|
||||
switch (*p++) {
|
||||
case 'l' :
|
||||
// could it be "lang."
|
||||
if (*p == 'a') { // "lang." ?
|
||||
if (recognize(p,"ang")) {
|
||||
p++;
|
||||
switch (*p++) {
|
||||
case 'n':
|
||||
if (recognize(p,"ame"))
|
||||
data.langName = value;
|
||||
else
|
||||
invalidItem = true;
|
||||
break;
|
||||
case 't':
|
||||
if (recognize(p,"ranslator")) {
|
||||
p++;
|
||||
if (recognize(p,"preprocesses"))
|
||||
data.TranslatorPreprocesses = getBoolean(value);
|
||||
else if (recognize(p, "optimizes"))
|
||||
data.TranslatorOptimizes = getBoolean(value);
|
||||
else if (recognize(p, "groks_dash_O"))
|
||||
data.TranslatorGroksDashO = getBoolean(value);
|
||||
else
|
||||
invalidItem = true;
|
||||
}
|
||||
else
|
||||
invalidItem = true;
|
||||
break;
|
||||
case 'p':
|
||||
if (recognize(p,"reprocessor")) {
|
||||
p++;
|
||||
if (recognize(p,"needed")) {
|
||||
data.PreprocessorNeeded = getBoolean(value);
|
||||
} else
|
||||
invalidItem = true;
|
||||
}
|
||||
else
|
||||
invalidItem = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
invalidItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (*p == 'i') { // "linker." ?
|
||||
if (recognize(p,"inker")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Linker.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Linker,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
}
|
||||
else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p' :
|
||||
if (*p == 'r') { // "preprocessor." ?
|
||||
if (recognize(p, "reprocessor")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.PreProcessor.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.PreProcessor,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 't' :
|
||||
if (*p == 'r') { // "translator." ?
|
||||
if (recognize(p, "ranslator")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Translator.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Translator,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o' :
|
||||
if (*p == 'p') { // "optimizer." ?
|
||||
if (recognize(p, "ptimizer")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Optimizer.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Optimizer,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
case 'a' :
|
||||
if (*p == 's') { // "assembler." ?
|
||||
if (recognize(p, "ssembler")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Assembler.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Assembler,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (invalidItem)
|
||||
provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos));
|
||||
}
|
||||
return new CompilerDriver::ConfigData(data);
|
||||
}
|
||||
|
||||
CompilerDriver::ConfigData*
|
||||
ReadConfigData(const std::string& ftype) {
|
||||
if ( ftype == "ll" ) {
|
||||
StaticInputProvider sip(LL_Data, sizeof(LL_Data)/sizeof(LL_Data[0]),
|
||||
"LLVM Assembly (internal)");
|
||||
return ParseConfigData(sip);
|
||||
} else if (ftype == "st") {
|
||||
StaticInputProvider sip(ST_Data, sizeof(ST_Data)/sizeof(ST_Data[0]),
|
||||
"Stacker (internal)");
|
||||
return ParseConfigData(sip);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
|
||||
: Configurations()
|
||||
, configDir()
|
||||
{
|
||||
Configurations.clear();
|
||||
}
|
||||
|
||||
LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
|
||||
{
|
||||
ConfigDataMap::iterator cIt = Configurations.begin();
|
||||
while (cIt != Configurations.end()) {
|
||||
CompilerDriver::ConfigData* cd = cIt->second;
|
||||
++cIt;
|
||||
delete cd;
|
||||
}
|
||||
Configurations.clear();
|
||||
}
|
||||
|
||||
CompilerDriver::ConfigData*
|
||||
LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
|
||||
CompilerDriver::ConfigData* result = 0;
|
||||
if (!Configurations.empty()) {
|
||||
ConfigDataMap::iterator cIt = Configurations.find(filetype);
|
||||
if ( cIt != Configurations.end() ) {
|
||||
// We found one in the case, return it.
|
||||
result = cIt->second;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
// The configuration data doesn't exist, we have to go read it.
|
||||
result = ReadConfigData(filetype);
|
||||
// If we got one, cache it
|
||||
if ( result != 0 )
|
||||
Configurations.insert(std::make_pair(filetype,result));
|
||||
}
|
||||
return result; // Might return 0
|
||||
}
|
||||
|
||||
// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
|
58
tools/llvmc/ConfigData.h
Normal file
58
tools/llvmc/ConfigData.h
Normal file
@ -0,0 +1,58 @@
|
||||
//===- ConfigData.h - Configuration Data Provider ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Reid Spencer and is distributed under the
|
||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the LLVMC_ConfigDataProvider class which implements the
|
||||
// generation of ConfigData objects for the CompilerDriver.
|
||||
//
|
||||
//===------------------------------------------------------------------------===
|
||||
#ifndef LLVM_TOOLS_LLVMC_CONFIGDATA_H
|
||||
#define LLVM_TOOLS_LLVMC_CONFIGDATA_H
|
||||
|
||||
#include "CompilerDriver.h"
|
||||
#include <Support/hash_map>
|
||||
|
||||
namespace llvm {
|
||||
/// This class provides the high level interface to the LLVM Compiler Driver.
|
||||
/// The driver's purpose is to make it easier for compiler writers and users
|
||||
/// of LLVM to utilize the compiler toolkits and LLVM toolset by learning only
|
||||
/// the interface of one program (llvmc).
|
||||
///
|
||||
/// @see llvmc.cpp
|
||||
/// @brief The interface to the LLVM Compiler Driver.
|
||||
class LLVMC_ConfigDataProvider : public CompilerDriver::ConfigDataProvider {
|
||||
/// @name Constructor
|
||||
/// @{
|
||||
public:
|
||||
LLVMC_ConfigDataProvider();
|
||||
virtual ~LLVMC_ConfigDataProvider();
|
||||
|
||||
/// @name Methods
|
||||
/// @{
|
||||
public:
|
||||
/// @brief Provide the configuration data to the CompilerDriver.
|
||||
virtual CompilerDriver::ConfigData*
|
||||
ProvideConfigData(const std::string& filetype);
|
||||
|
||||
/// @brief Allow the configuration directory to be set
|
||||
virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
|
||||
|
||||
/// @}
|
||||
/// @name Data
|
||||
/// @{
|
||||
private:
|
||||
/// @brief This type is used internally to hold the configuration data.
|
||||
typedef hash_map<std::string,CompilerDriver::ConfigData*,
|
||||
hash<std::string>,std::equal_to<std::string> > ConfigDataMap;
|
||||
ConfigDataMap Configurations; ///< The cache of configurations
|
||||
std::string configDir;
|
||||
/// @}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
441
tools/llvmc/Configuration.cpp
Normal file
441
tools/llvmc/Configuration.cpp
Normal file
@ -0,0 +1,441 @@
|
||||
//===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Reid Spencer and is distributed under the
|
||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the parsing of configuration files for the LLVM Compiler
|
||||
// Driver (llvmc).
|
||||
//
|
||||
//===------------------------------------------------------------------------===
|
||||
|
||||
#include "ConfigData.h"
|
||||
#include "CompilerDriver.h"
|
||||
#include "Support/StringExtras.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
// This array of strings provides the input for ".ll" files (LLVM Assembly)
|
||||
// to the configuration file parser. This data is just "built-in" to
|
||||
// llvmc so it doesn't have to be read from a configuration file.
|
||||
static const char* LL_Data[] = {
|
||||
"lang.name=LLVM Assembly",
|
||||
"lang.translator.preprocesses=false",
|
||||
"lang.translator.optimizes=No",
|
||||
"lang.translator.groks_dash_O=No",
|
||||
"lang.preprocessor.needed=0",
|
||||
"preprocessor.prog=",
|
||||
"preprocessor.args=",
|
||||
"translator.prog=llvm-as",
|
||||
"translator.args=@in@ -o @out@",
|
||||
"optimizer.prog=opt",
|
||||
"optimizer.args=@in@ -o @out@",
|
||||
"assembler.prog=llc",
|
||||
"assembler.args=@in@ -o @out@",
|
||||
"linker.prog=llvm-link",
|
||||
"linker.args=@in@ -o @out@"
|
||||
};
|
||||
|
||||
// This array of strings provides the input for ".st" files (Stacker).
|
||||
static const char* ST_Data[] = {
|
||||
"lang.name=Stacker",
|
||||
"lang.translator.preprocesses=false",
|
||||
"lang.translator.optimizes=true",
|
||||
"lang.translator.groks_dash_O=0",
|
||||
"lang.preprocessor.needed=0",
|
||||
"preprocessor.prog=cp",
|
||||
"preprocessor.args=@in@ @out@",
|
||||
"translator.prog=stkrc",
|
||||
"translator.args=@in@ -o @out@ -S 2048",
|
||||
"optimizer.prog=opt",
|
||||
"optimizer.args=@in@ -o @out@",
|
||||
"assembler.prog=llc",
|
||||
"assembler.args=@in@ -o @out@",
|
||||
"linker.prog=llvm-link",
|
||||
"linker.args=@in@ -o @out@"
|
||||
};
|
||||
|
||||
class InputProvider {
|
||||
public:
|
||||
virtual bool getLine(std::string& line) = 0;
|
||||
virtual void error(const std::string& msg) = 0;
|
||||
virtual bool errorOccurred() = 0;
|
||||
};
|
||||
|
||||
class StaticInputProvider : public InputProvider {
|
||||
public:
|
||||
StaticInputProvider(const char *data[], size_t count,
|
||||
const std::string& nam) {
|
||||
TheData = data;
|
||||
limit = count;
|
||||
where = 0;
|
||||
name = nam;
|
||||
errCount = 0;
|
||||
}
|
||||
virtual ~StaticInputProvider() {}
|
||||
virtual bool getLine(std::string& line) {
|
||||
if ( where >= limit ) return false;
|
||||
line = TheData[where++];
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void error(const std::string& msg) {
|
||||
std::cerr << name << ":" << where << ": Error: " << msg << "\n";
|
||||
errCount++;
|
||||
}
|
||||
|
||||
virtual bool errorOccurred() { return errCount > 0; };
|
||||
|
||||
private:
|
||||
const char**TheData;
|
||||
size_t limit;
|
||||
size_t where;
|
||||
std::string name;
|
||||
size_t errCount;
|
||||
};
|
||||
|
||||
inline bool recognize(const char*& p, const char*token) {
|
||||
while (*p == *token && *token != '\0')
|
||||
++token, p++;
|
||||
return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
|
||||
}
|
||||
|
||||
inline bool getBoolean(const std::string& value) {
|
||||
switch (value[0]) {
|
||||
case 't':
|
||||
case 'T':
|
||||
case '1':
|
||||
case 'y':
|
||||
case 'Y':
|
||||
return true;
|
||||
default :
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void skipWhitespace( size_t& pos, const std::string& line ) {
|
||||
while (pos < line.size() && (
|
||||
line[pos] == ' ' || // Space
|
||||
line[pos] == '\t' || // Horizontal Tab
|
||||
line[pos] == '\n' || // New Line
|
||||
line[pos] == '\v' || // Vertical Tab
|
||||
line[pos] == '\f' || // Form Feed
|
||||
line[pos] == '\r') // Carriate Return
|
||||
)
|
||||
pos++;
|
||||
}
|
||||
|
||||
inline void parseArgs(CompilerDriver::Action& pat,
|
||||
const std::string& value,
|
||||
InputProvider& provider )
|
||||
{
|
||||
const char* p = value.c_str();
|
||||
const char* argStart = p;
|
||||
while (*p != '\0') {
|
||||
switch (*p) {
|
||||
case ' ':
|
||||
if (argStart != p)
|
||||
pat.args.push_back(std::string(argStart, p-argStart));
|
||||
argStart = ++p;
|
||||
break;
|
||||
case '@' :
|
||||
{
|
||||
if (argStart != p)
|
||||
pat.args.push_back(std::string(argStart,p-argStart));
|
||||
const char* token = ++p;
|
||||
while (*p != '@' && *p != 0)
|
||||
p++;
|
||||
if ( *p != '@' ) {
|
||||
provider.error("Unterminated substitution token");
|
||||
return;
|
||||
} else {
|
||||
p++;
|
||||
bool legal = false;
|
||||
switch (token[0]) {
|
||||
case 'i':
|
||||
if (token[1] == 'n' && token[2] == '@' ) {
|
||||
pat.inputAt = pat.args.size();
|
||||
pat.args.push_back("in");
|
||||
legal = true;
|
||||
argStart = p;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (token[1] == 'u' && token[2] == 't' && token[3] == '@') {
|
||||
pat.outputAt = pat.args.size();
|
||||
pat.args.push_back("out");
|
||||
legal = true;
|
||||
argStart = p;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!legal) {
|
||||
provider.error("Invalid substitution token");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default :
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CompilerDriver::ConfigData*
|
||||
ParseConfigData(InputProvider& provider) {
|
||||
std::string line;
|
||||
CompilerDriver::ConfigData data;
|
||||
while ( provider.getLine(line) ) {
|
||||
// Check line length first
|
||||
size_t lineLen = line.size();
|
||||
if (lineLen > 4096)
|
||||
provider.error("length of input line (" + utostr(lineLen) +
|
||||
") is too long");
|
||||
|
||||
// First, skip whitespace
|
||||
size_t stPos = 0;
|
||||
skipWhitespace(stPos, line);
|
||||
|
||||
// See if there's a hash mark. It and everything after it is
|
||||
// ignored so lets delete that now.
|
||||
size_t hashPos = line.find('#');
|
||||
if (hashPos != std::string::npos)
|
||||
line.erase(hashPos);
|
||||
|
||||
// Make sure we have something left to parse
|
||||
if (line.size() == 0)
|
||||
continue; // ignore full-line comment or whitespace line
|
||||
|
||||
// Find the equals sign
|
||||
size_t eqPos = line.find('=');
|
||||
if (eqPos == std::string::npos)
|
||||
provider.error("Configuration directive is missing an =");
|
||||
|
||||
// extract the item name
|
||||
std::string name(line, stPos, eqPos-stPos);
|
||||
|
||||
// directives without names are illegal
|
||||
if (name.empty())
|
||||
provider.error("Configuration directive name is empty");
|
||||
|
||||
// Skip whitespace in the value
|
||||
size_t valPos = eqPos + 1;
|
||||
skipWhitespace(valPos, line);
|
||||
|
||||
// Skip white space at end of value
|
||||
size_t endPos = line.length() - 1;
|
||||
while (line[endPos] == ' ')
|
||||
endPos--;
|
||||
|
||||
// extract the item value
|
||||
std::string value(line, valPos, endPos-valPos+1);
|
||||
|
||||
// Get the configuration item as a char pointer
|
||||
const char*p = name.c_str();
|
||||
|
||||
// Indicate we haven't found an invalid item yet.
|
||||
bool invalidItem = false;
|
||||
|
||||
// Parse the contents by examining first character and
|
||||
// using the recognize function strategically
|
||||
switch (*p++) {
|
||||
case 'l' :
|
||||
// could it be "lang."
|
||||
if (*p == 'a') { // "lang." ?
|
||||
if (recognize(p,"ang")) {
|
||||
p++;
|
||||
switch (*p++) {
|
||||
case 'n':
|
||||
if (recognize(p,"ame"))
|
||||
data.langName = value;
|
||||
else
|
||||
invalidItem = true;
|
||||
break;
|
||||
case 't':
|
||||
if (recognize(p,"ranslator")) {
|
||||
p++;
|
||||
if (recognize(p,"preprocesses"))
|
||||
data.TranslatorPreprocesses = getBoolean(value);
|
||||
else if (recognize(p, "optimizes"))
|
||||
data.TranslatorOptimizes = getBoolean(value);
|
||||
else if (recognize(p, "groks_dash_O"))
|
||||
data.TranslatorGroksDashO = getBoolean(value);
|
||||
else
|
||||
invalidItem = true;
|
||||
}
|
||||
else
|
||||
invalidItem = true;
|
||||
break;
|
||||
case 'p':
|
||||
if (recognize(p,"reprocessor")) {
|
||||
p++;
|
||||
if (recognize(p,"needed")) {
|
||||
data.PreprocessorNeeded = getBoolean(value);
|
||||
} else
|
||||
invalidItem = true;
|
||||
}
|
||||
else
|
||||
invalidItem = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
invalidItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (*p == 'i') { // "linker." ?
|
||||
if (recognize(p,"inker")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Linker.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Linker,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
}
|
||||
else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p' :
|
||||
if (*p == 'r') { // "preprocessor." ?
|
||||
if (recognize(p, "reprocessor")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.PreProcessor.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.PreProcessor,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 't' :
|
||||
if (*p == 'r') { // "translator." ?
|
||||
if (recognize(p, "ranslator")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Translator.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Translator,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o' :
|
||||
if (*p == 'p') { // "optimizer." ?
|
||||
if (recognize(p, "ptimizer")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Optimizer.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Optimizer,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
case 'a' :
|
||||
if (*p == 's') { // "assembler." ?
|
||||
if (recognize(p, "ssembler")) {
|
||||
p++;
|
||||
if (recognize(p,"prog"))
|
||||
data.Assembler.program = value;
|
||||
else if (recognize(p,"args"))
|
||||
parseArgs(data.Assembler,value,provider);
|
||||
else
|
||||
invalidItem = true;
|
||||
} else
|
||||
invalidItem = true;
|
||||
} else {
|
||||
invalidItem = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (invalidItem)
|
||||
provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos));
|
||||
}
|
||||
return new CompilerDriver::ConfigData(data);
|
||||
}
|
||||
|
||||
CompilerDriver::ConfigData*
|
||||
ReadConfigData(const std::string& ftype) {
|
||||
if ( ftype == "ll" ) {
|
||||
StaticInputProvider sip(LL_Data, sizeof(LL_Data)/sizeof(LL_Data[0]),
|
||||
"LLVM Assembly (internal)");
|
||||
return ParseConfigData(sip);
|
||||
} else if (ftype == "st") {
|
||||
StaticInputProvider sip(ST_Data, sizeof(ST_Data)/sizeof(ST_Data[0]),
|
||||
"Stacker (internal)");
|
||||
return ParseConfigData(sip);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
|
||||
: Configurations()
|
||||
, configDir()
|
||||
{
|
||||
Configurations.clear();
|
||||
}
|
||||
|
||||
LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
|
||||
{
|
||||
ConfigDataMap::iterator cIt = Configurations.begin();
|
||||
while (cIt != Configurations.end()) {
|
||||
CompilerDriver::ConfigData* cd = cIt->second;
|
||||
++cIt;
|
||||
delete cd;
|
||||
}
|
||||
Configurations.clear();
|
||||
}
|
||||
|
||||
CompilerDriver::ConfigData*
|
||||
LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
|
||||
CompilerDriver::ConfigData* result = 0;
|
||||
if (!Configurations.empty()) {
|
||||
ConfigDataMap::iterator cIt = Configurations.find(filetype);
|
||||
if ( cIt != Configurations.end() ) {
|
||||
// We found one in the case, return it.
|
||||
result = cIt->second;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
// The configuration data doesn't exist, we have to go read it.
|
||||
result = ReadConfigData(filetype);
|
||||
// If we got one, cache it
|
||||
if ( result != 0 )
|
||||
Configurations.insert(std::make_pair(filetype,result));
|
||||
}
|
||||
return result; // Might return 0
|
||||
}
|
||||
|
||||
// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
|
58
tools/llvmc/Configuration.h
Normal file
58
tools/llvmc/Configuration.h
Normal file
@ -0,0 +1,58 @@
|
||||
//===- ConfigData.h - Configuration Data Provider ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by Reid Spencer and is distributed under the
|
||||
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the LLVMC_ConfigDataProvider class which implements the
|
||||
// generation of ConfigData objects for the CompilerDriver.
|
||||
//
|
||||
//===------------------------------------------------------------------------===
|
||||
#ifndef LLVM_TOOLS_LLVMC_CONFIGDATA_H
|
||||
#define LLVM_TOOLS_LLVMC_CONFIGDATA_H
|
||||
|
||||
#include "CompilerDriver.h"
|
||||
#include <Support/hash_map>
|
||||
|
||||
namespace llvm {
|
||||
/// This class provides the high level interface to the LLVM Compiler Driver.
|
||||
/// The driver's purpose is to make it easier for compiler writers and users
|
||||
/// of LLVM to utilize the compiler toolkits and LLVM toolset by learning only
|
||||
/// the interface of one program (llvmc).
|
||||
///
|
||||
/// @see llvmc.cpp
|
||||
/// @brief The interface to the LLVM Compiler Driver.
|
||||
class LLVMC_ConfigDataProvider : public CompilerDriver::ConfigDataProvider {
|
||||
/// @name Constructor
|
||||
/// @{
|
||||
public:
|
||||
LLVMC_ConfigDataProvider();
|
||||
virtual ~LLVMC_ConfigDataProvider();
|
||||
|
||||
/// @name Methods
|
||||
/// @{
|
||||
public:
|
||||
/// @brief Provide the configuration data to the CompilerDriver.
|
||||
virtual CompilerDriver::ConfigData*
|
||||
ProvideConfigData(const std::string& filetype);
|
||||
|
||||
/// @brief Allow the configuration directory to be set
|
||||
virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
|
||||
|
||||
/// @}
|
||||
/// @name Data
|
||||
/// @{
|
||||
private:
|
||||
/// @brief This type is used internally to hold the configuration data.
|
||||
typedef hash_map<std::string,CompilerDriver::ConfigData*,
|
||||
hash<std::string>,std::equal_to<std::string> > ConfigDataMap;
|
||||
ConfigDataMap Configurations; ///< The cache of configurations
|
||||
std::string configDir;
|
||||
/// @}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user