mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-15 07:39:31 +00:00
Converted to use flex for tokenizing input so we can use an easier to
understand recursive descent parser, we can easily handle more syntax variety, and we can more easily change the configuration items accepted. llvm-svn: 15732
This commit is contained in:
parent
fe43dbee67
commit
737adb695d
@ -29,8 +29,38 @@ namespace {
|
||||
if ( dotpos = std::string::npos ) return "";
|
||||
return fullName.substr(dotpos+1);
|
||||
}
|
||||
|
||||
const char OutputSuffix[] = ".o";
|
||||
|
||||
void WriteAction(CompilerDriver::Action* a) {
|
||||
std::cerr << a->program;
|
||||
std::vector<std::string>::iterator I = a->args.begin();
|
||||
while (I != a->args.end()) {
|
||||
std::cerr << " " + *I;
|
||||
++I;
|
||||
}
|
||||
std::cerr << "\n";
|
||||
}
|
||||
|
||||
void DumpConfigData(CompilerDriver::ConfigData* cd, const std::string& type ){
|
||||
std::cerr << "Configuration Data For '" << cd->langName << "' (" << type
|
||||
<< ")\n";
|
||||
std::cerr << "translator.preprocesses=" << cd->TranslatorPreprocesses
|
||||
<< "\n";
|
||||
std::cerr << "translator.groks_dash_O=" << cd->TranslatorGroksDashO << "\n";
|
||||
std::cerr << "translator.optimizes=" << cd->TranslatorOptimizes << "\n";
|
||||
std::cerr << "preprocessor.needed=" << cd->PreprocessorNeeded << "\n";
|
||||
std::cerr << "PreProcessor: ";
|
||||
WriteAction(&cd->PreProcessor);
|
||||
std::cerr << "Translator: ";
|
||||
WriteAction(&cd->Translator);
|
||||
std::cerr << "Optimizer: ";
|
||||
WriteAction(&cd->Optimizer);
|
||||
std::cerr << "Assembler: ";
|
||||
WriteAction(&cd->Assembler);
|
||||
std::cerr << "Linker: ";
|
||||
WriteAction(&cd->Linker);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -80,21 +110,13 @@ CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd,
|
||||
}
|
||||
assert(pat != 0 && "Invalid command pattern");
|
||||
Action* a = new Action(*pat);
|
||||
a->args[pat->inputAt] = input;
|
||||
a->args[pat->outputAt] = output;
|
||||
if (pat->inputAt < a->args.size())
|
||||
a->args[pat->inputAt] = input;
|
||||
if (pat->outputAt < a->args.size())
|
||||
a->args[pat->outputAt] = output;
|
||||
return a;
|
||||
}
|
||||
|
||||
void CompilerDriver::WriteAction(Action* a) {
|
||||
std::cerr << a->program;
|
||||
std::vector<std::string>::iterator I = a->args.begin();
|
||||
while (I != a->args.end()) {
|
||||
std::cerr << " " + *I;
|
||||
++I;
|
||||
}
|
||||
std::cerr << "\n";
|
||||
}
|
||||
|
||||
void CompilerDriver::DoAction(Action*a)
|
||||
{
|
||||
if (isVerbose)
|
||||
@ -170,6 +192,8 @@ int CompilerDriver::execute(const InputList& InpList,
|
||||
if (cd == 0)
|
||||
error(std::string("Files of type '") + I->second +
|
||||
"' are not recognized." );
|
||||
if (isDebug)
|
||||
DumpConfigData(cd,I->second);
|
||||
|
||||
// We have valid configuration data, now figure out where the output
|
||||
// of compilation should end up.
|
||||
|
@ -58,6 +58,7 @@ namespace llvm {
|
||||
/// @brief A structure to hold the action data for a given source
|
||||
/// language.
|
||||
struct Action {
|
||||
Action() : inputAt(0) , outputAt(0) {}
|
||||
std::string program; ///< The program to execve
|
||||
std::vector<std::string> args; ///< Arguments to the program
|
||||
size_t inputAt; ///< Argument index to insert input file
|
||||
@ -65,6 +66,10 @@ namespace llvm {
|
||||
};
|
||||
|
||||
struct ConfigData {
|
||||
ConfigData() : TranslatorPreprocesses(false),
|
||||
TranslatorOptimizes(false),
|
||||
TranslatorGroksDashO(false),
|
||||
PreprocessorNeeded(false) {}
|
||||
std::string langName; ///< The name of the source language
|
||||
bool TranslatorPreprocesses;///< Translator program will pre-process
|
||||
bool TranslatorOptimizes; ///< Translator program will optimize too
|
||||
@ -155,7 +160,6 @@ namespace llvm {
|
||||
private:
|
||||
Action* GetAction(ConfigData* cd, const std::string& input,
|
||||
const std::string& output, Phases phase );
|
||||
void WriteAction(Action* a);
|
||||
void DoAction(Action* a);
|
||||
|
||||
/// @}
|
||||
|
@ -13,391 +13,282 @@
|
||||
//===------------------------------------------------------------------------===
|
||||
|
||||
#include "ConfigData.h"
|
||||
#include "ConfigLexer.h"
|
||||
#include "CompilerDriver.h"
|
||||
#include "Support/StringExtras.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
extern int ::Configlex();
|
||||
|
||||
namespace llvm {
|
||||
ConfigLexerInfo ConfigLexerData;
|
||||
InputProvider* ConfigLexerInput = 0;
|
||||
unsigned ConfigLexerLine = 1;
|
||||
|
||||
InputProvider::~InputProvider() {}
|
||||
void InputProvider::error(const std::string& msg) {
|
||||
std::cerr << name << ":" << ConfigLexerLine << ": Error: " << msg << "\n";
|
||||
errCount++;
|
||||
}
|
||||
|
||||
void InputProvider::checkErrors() {
|
||||
if (errCount > 0) {
|
||||
std::cerr << name << " had " << errCount << " errors. Terminating.\n";
|
||||
exit(errCount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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@"
|
||||
};
|
||||
class FileInputProvider : public InputProvider {
|
||||
public:
|
||||
FileInputProvider(const std::string & fname)
|
||||
: InputProvider(fname)
|
||||
, F(fname.c_str()) {
|
||||
ConfigLexerInput = this;
|
||||
}
|
||||
virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
|
||||
virtual unsigned read(char *buffer, unsigned max_size) {
|
||||
if (F.good()) {
|
||||
F.read(buffer,max_size);
|
||||
if ( F.gcount() ) return F.gcount() - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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@"
|
||||
};
|
||||
bool okay() { return F.good(); }
|
||||
private:
|
||||
std::ifstream F;
|
||||
};
|
||||
|
||||
class InputProvider {
|
||||
public:
|
||||
virtual bool getLine(std::string& line) = 0;
|
||||
virtual void error(const std::string& msg) = 0;
|
||||
virtual bool errorOccurred() = 0;
|
||||
};
|
||||
struct ParseContext
|
||||
{
|
||||
int token;
|
||||
InputProvider* provider;
|
||||
CompilerDriver::ConfigData* confDat;
|
||||
CompilerDriver::Action* action;
|
||||
|
||||
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;
|
||||
int next() { return token = Configlex(); }
|
||||
|
||||
bool next_is_real() {
|
||||
token = Configlex();
|
||||
return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
|
||||
}
|
||||
|
||||
virtual void error(const std::string& msg) {
|
||||
std::cerr << name << ":" << where << ": Error: " << msg << "\n";
|
||||
errCount++;
|
||||
void eatLineRemnant() {
|
||||
while (next_is_real()) ;
|
||||
}
|
||||
|
||||
virtual bool errorOccurred() { return errCount > 0; };
|
||||
void error(const std::string& msg, bool skip = true) {
|
||||
provider->error(msg);
|
||||
if (skip)
|
||||
eatLineRemnant();
|
||||
}
|
||||
|
||||
private:
|
||||
const char**TheData;
|
||||
size_t limit;
|
||||
size_t where;
|
||||
std::string name;
|
||||
size_t errCount;
|
||||
};
|
||||
std::string parseName() {
|
||||
std::string result;
|
||||
if (next() == EQUALS) {
|
||||
while (next_is_real()) {
|
||||
switch (token ) {
|
||||
case STRING :
|
||||
case OPTION :
|
||||
result += ConfigLexerData.StringVal + " ";
|
||||
break;
|
||||
default:
|
||||
error("Invalid name");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result.empty())
|
||||
error("Name exepected");
|
||||
else
|
||||
result.erase(result.size()-1,1);
|
||||
} else
|
||||
error("= expected");
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool recognize(const char*& p, const char*token) {
|
||||
while (*p == *token && *token != '\0')
|
||||
++token, p++;
|
||||
return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
|
||||
}
|
||||
bool parseBoolean() {
|
||||
bool result = true;
|
||||
if (next() == EQUALS) {
|
||||
if (next() == FALSETOK) {
|
||||
result = false;
|
||||
} else if (token != TRUETOK) {
|
||||
error("Expecting boolean value");
|
||||
return false;
|
||||
}
|
||||
if (next() != EOLTOK && token != 0) {
|
||||
error("Extraneous tokens after boolean");
|
||||
}
|
||||
}
|
||||
else
|
||||
error("Expecting '='");
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void parseLang() {
|
||||
if ( next() == NAME ) {
|
||||
confDat->langName = parseName();
|
||||
} else if (token == TRANSLATOR) {
|
||||
switch (next()) {
|
||||
case PREPROCESSES:
|
||||
confDat->TranslatorPreprocesses = parseBoolean();
|
||||
break;
|
||||
case OPTIMIZES:
|
||||
confDat->TranslatorOptimizes = parseBoolean();
|
||||
break;
|
||||
case GROKS_DASH_O:
|
||||
confDat->TranslatorGroksDashO = parseBoolean();
|
||||
break;
|
||||
default:
|
||||
error("Invalid lang.translator identifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (token == PREPROCESSOR) {
|
||||
if (next() == NEEDED)
|
||||
confDat->PreprocessorNeeded = parseBoolean();
|
||||
}
|
||||
else {
|
||||
error("Expecting valid identifier after 'lang.'");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
void parseCommand(CompilerDriver::Action& action) {
|
||||
if (next() == EQUALS) {
|
||||
next();
|
||||
if (token == EOLTOK) {
|
||||
// no value (valid)
|
||||
action.program.clear();
|
||||
action.args.clear();
|
||||
action.inputAt = 0;
|
||||
action.outputAt = 0;
|
||||
} else {
|
||||
if (token == STRING || token == OPTION) {
|
||||
action.program = ConfigLexerData.StringVal;
|
||||
} 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;
|
||||
}
|
||||
error("Expecting a program name");
|
||||
}
|
||||
while (next_is_real()) {
|
||||
if (token == STRING || token == OPTION)
|
||||
action.args.push_back(ConfigLexerData.StringVal);
|
||||
else if (token == IN_SUBST) {
|
||||
action.inputAt = action.args.size();
|
||||
action.args.push_back("in");
|
||||
} else if (token == OUT_SUBST) {
|
||||
action.outputAt = action.args.size();
|
||||
action.args.push_back("out");
|
||||
} else
|
||||
error("Expecting a program argument", false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default :
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void parsePreProcessor() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->PreProcessor);
|
||||
}
|
||||
|
||||
void parseTranslator() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Translator);
|
||||
}
|
||||
|
||||
void parseOptimizer() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Optimizer);
|
||||
}
|
||||
|
||||
void parseAssembler() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Assembler);
|
||||
}
|
||||
|
||||
void parseLinker() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Linker);
|
||||
}
|
||||
|
||||
void parseAssignment() {
|
||||
switch (token) {
|
||||
case LANG: return parseLang();
|
||||
case PREPROCESSOR: return parsePreProcessor();
|
||||
case TRANSLATOR: return parseTranslator();
|
||||
case OPTIMIZER: return parseOptimizer();
|
||||
case ASSEMBLER: return parseAssembler();
|
||||
case LINKER: return parseLinker();
|
||||
case EOLTOK: break; // just ignore
|
||||
case ERRORTOK:
|
||||
default:
|
||||
error("Invalid top level configuration item identifier");
|
||||
}
|
||||
}
|
||||
|
||||
void parseFile() {
|
||||
while ( next() != 0 ) {
|
||||
parseAssignment();
|
||||
}
|
||||
provider->checkErrors();
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
|
||||
ParseContext ctxt;
|
||||
ctxt.token = 0;
|
||||
ctxt.provider = &provider;
|
||||
ctxt.confDat = &confDat;
|
||||
ctxt.action = 0;
|
||||
ctxt.parseFile();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
|
||||
CompilerDriver::ConfigData* result = 0;
|
||||
if (configDir.empty()) {
|
||||
FileInputProvider fip( std::string("/etc/llvm/") + ftype );
|
||||
if (!fip.okay()) {
|
||||
fip.error("Configuration for '" + ftype + "' is not available.");
|
||||
fip.checkErrors();
|
||||
}
|
||||
else {
|
||||
result = new CompilerDriver::ConfigData();
|
||||
ParseConfigData(fip,*result);
|
||||
}
|
||||
} else {
|
||||
FileInputProvider fip( configDir + "/" + ftype );
|
||||
if (!fip.okay()) {
|
||||
fip.error("Configuration for '" + ftype + "' is not available.");
|
||||
fip.checkErrors();
|
||||
}
|
||||
else {
|
||||
result = new CompilerDriver::ConfigData();
|
||||
ParseConfigData(fip,*result);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
|
||||
|
@ -42,6 +42,9 @@ namespace llvm {
|
||||
/// @brief Allow the configuration directory to be set
|
||||
virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
|
||||
|
||||
private:
|
||||
CompilerDriver::ConfigData* ReadConfigData(const std::string& ftype);
|
||||
|
||||
/// @}
|
||||
/// @name Data
|
||||
/// @{
|
||||
|
77
tools/llvmc/ConfigLexer.h
Normal file
77
tools/llvmc/ConfigLexer.h
Normal file
@ -0,0 +1,77 @@
|
||||
//===- ConfigLexer.h - ConfigLexer Declarations -----------------*- 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 types and data needed by ConfigLexer.l
|
||||
//
|
||||
//===------------------------------------------------------------------------===
|
||||
#ifndef LLVM_TOOLS_LLVMC_CONFIGLEXER_H
|
||||
#define LLVM_TOOLS_LLVMC_CONFIGLEXER_H
|
||||
|
||||
#include <string>
|
||||
#include <istream>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct ConfigLexerInfo
|
||||
{
|
||||
int64_t IntegerVal;
|
||||
std::string StringVal;
|
||||
};
|
||||
|
||||
extern ConfigLexerInfo ConfigLexerData;
|
||||
extern unsigned ConfigLexerLine;
|
||||
|
||||
class InputProvider {
|
||||
public:
|
||||
InputProvider(const std::string& nm) {
|
||||
name = nm;
|
||||
errCount = 0;
|
||||
}
|
||||
virtual ~InputProvider();
|
||||
virtual unsigned read(char *buf, unsigned max_size) = 0;
|
||||
virtual void error(const std::string& msg);
|
||||
virtual void checkErrors();
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
unsigned errCount;
|
||||
};
|
||||
|
||||
extern InputProvider* ConfigLexerInput;
|
||||
|
||||
enum ConfigLexerTokens {
|
||||
EOFTOK = 0, ///< Returned by Configlex when we hit end of file
|
||||
EOLTOK, ///< End of line
|
||||
ERRORTOK, ///< Error token
|
||||
OPTION, ///< A command line option
|
||||
SEPARATOR, ///< A configuration item separator
|
||||
EQUALS, ///< The equals sign, =
|
||||
TRUETOK, ///< A boolean true value (true/yes/on)
|
||||
FALSETOK, ///< A boolean false value (false/no/off)
|
||||
INTEGER, ///< An integer
|
||||
STRING, ///< A quoted string
|
||||
IN_SUBST, ///< The input substitution item @in@
|
||||
OUT_SUBST, ///< The output substitution item @out@
|
||||
LANG, ///< The item "lang" (and case variants)
|
||||
PREPROCESSOR, ///< The item "preprocessor" (and case variants)
|
||||
TRANSLATOR, ///< The item "translator" (and case variants)
|
||||
OPTIMIZER, ///< The item "optimizer" (and case variants)
|
||||
ASSEMBLER, ///< The item "assembler" (and case variants)
|
||||
LINKER, ///< The item "linker" (and case variants)
|
||||
NAME, ///< The item "name" (and case variants)
|
||||
NEEDED, ///< The item "needed" (and case variants)
|
||||
COMMAND, ///< The item "command" (and case variants)
|
||||
PREPROCESSES, ///< The item "preprocesses" (and case variants)
|
||||
GROKS_DASH_O, ///< The item "groks_dash_O" (and case variants)
|
||||
OPTIMIZES, ///< The item "optimizes" (and case variants)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
135
tools/llvmc/ConfigLexer.l
Normal file
135
tools/llvmc/ConfigLexer.l
Normal file
@ -0,0 +1,135 @@
|
||||
/*===- ConfigLexer.l - Scanner for CompilerDriver Config Files -*- 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 flex scanner for configuration files for the
|
||||
// llvmc CompilerDriver.
|
||||
//
|
||||
//===----------------------------------------------------------------------===*/
|
||||
|
||||
|
||||
%option prefix="Config"
|
||||
%option yylineno
|
||||
%option nostdinit
|
||||
%option never-interactive
|
||||
%option batch
|
||||
%option noyywrap
|
||||
%option nodefault
|
||||
%option 8bit
|
||||
%option outfile="ConfigLexer.cpp"
|
||||
%option ecs
|
||||
%option noreject
|
||||
%option noyymore
|
||||
%array
|
||||
|
||||
%{
|
||||
|
||||
#include "ConfigLexer.h"
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
{ \
|
||||
assert(ConfigLexerInput != 0 && "Oops"); \
|
||||
result = ConfigLexerInput->read(buf,max_size); \
|
||||
if (result == 0 ) result = YY_NULL; \
|
||||
}
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/* Conversion of text ints to binary */
|
||||
static int64_t IntToVal(const char *Buffer) {
|
||||
int64_t Result = 0;
|
||||
for (; *Buffer; Buffer++) {
|
||||
int64_t OldRes = Result;
|
||||
Result *= 10;
|
||||
Result += *Buffer-'0';
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool in_value = false;
|
||||
|
||||
%}
|
||||
|
||||
LANG lang|Lang|LANG
|
||||
PREPROCESSOR preprocessor|PreProcessor|PREPROCESSOR
|
||||
TRANSLATOR translator|Translator|TRANSLATOR
|
||||
OPTIMIZER optimizer|Optimizer|OPTIMIZER
|
||||
ASSEMBLER assembler|Assembler|ASSEMBLER
|
||||
LINKER linker|Linker|LINKER
|
||||
NAME name|Name|NAME
|
||||
NEEDED needed|Needed|NEEDED
|
||||
COMMAND command|Command|COMMAND
|
||||
PREPROCESSES preprocesses|PreProcesses|PREPROCESSES
|
||||
GROKS_DASH_O groks_dash_O|Groks_Dash_O|GROKS_DASH_O
|
||||
OPTIMIZES optimizes|Optimizes|OPTIMIZES
|
||||
Comment \#[^\n]*
|
||||
NewLine \n
|
||||
White [ \t]*
|
||||
Option [-A-Za-z0-9_:%+/\\|,]*
|
||||
Sep \.
|
||||
Eq \=
|
||||
String \"[^\"]*\"
|
||||
Integer [-+]?[0-9]+
|
||||
True true|True|TRUE
|
||||
False false|False|FALSE
|
||||
On on|On|ON
|
||||
Off off|Off|OFF
|
||||
Yes yes|Yes|YES
|
||||
No no|No|NO
|
||||
|
||||
%%
|
||||
|
||||
{NewLine} { in_value = false; ConfigLexerLine++; return EOLTOK; }
|
||||
{Comment} { /* Ignore comments */ }
|
||||
{White} { /* Ignore whitespace */ }
|
||||
|
||||
{LANG} { if (in_value) { ConfigLexerData.StringVal = "lang";
|
||||
return OPTION; } else return LANG; }
|
||||
{PREPROCESSOR} { if (in_value) { ConfigLexerData.StringVal = "preprocessor";
|
||||
return OPTION; } else return PREPROCESSOR; }
|
||||
{TRANSLATOR} { if (in_value) { ConfigLexerData.StringVal = "translator";
|
||||
return OPTION; } else return TRANSLATOR; }
|
||||
{OPTIMIZER} { if (in_value) { ConfigLexerData.StringVal = "optimizer";
|
||||
return OPTION; } else return OPTIMIZER; }
|
||||
{ASSEMBLER} { if (in_value) { ConfigLexerData.StringVal = "assembler";
|
||||
return OPTION; } else return ASSEMBLER; }
|
||||
{LINKER} { if (in_value) { ConfigLexerData.StringVal = "linker";
|
||||
return OPTION; } else return LINKER; }
|
||||
{NAME} { if (in_value) { ConfigLexerData.StringVal = "name";
|
||||
return OPTION; } else return NAME; }
|
||||
{NEEDED} { if (in_value) { ConfigLexerData.StringVal = "needed";
|
||||
return OPTION; } else return NEEDED; }
|
||||
{COMMAND} { if (in_value) { ConfigLexerData.StringVal = "command";
|
||||
return OPTION; } else return COMMAND; }
|
||||
{PREPROCESSES} { if (in_value) { ConfigLexerData.StringVal = "preprocesses";
|
||||
return OPTION; } else return PREPROCESSES; }
|
||||
{GROKS_DASH_O} { if (in_value) { ConfigLexerData.StringVal = "groks_dash_O";
|
||||
return OPTION; } else return GROKS_DASH_O; }
|
||||
{OPTIMIZES} { if (in_value) { ConfigLexerData.StringVal = "optimizes";
|
||||
return OPTION; } else return OPTIMIZES; }
|
||||
{Sep} { if (in_value) { ConfigLexerData.StringVal = yytext;
|
||||
return OPTION; } }
|
||||
|
||||
@in@ { if (in_value) return IN_SUBST; else return ERRORTOK; }
|
||||
@out@ { if (in_value) return OUT_SUBST; else return ERRORTOK; }
|
||||
{True} { if (in_value) return TRUETOK; else return ERRORTOK; }
|
||||
{On} { if (in_value) return TRUETOK; else return ERRORTOK; }
|
||||
{Yes} { if (in_value) return TRUETOK; else return ERRORTOK; }
|
||||
{False} { if (in_value) return FALSETOK; else return ERRORTOK; }
|
||||
{Off} { if (in_value) return FALSETOK; else return ERRORTOK; }
|
||||
{No} { if (in_value) return FALSETOK; else return ERRORTOK; }
|
||||
|
||||
{Eq} { in_value = true; return EQUALS; }
|
||||
{Option} { ConfigLexerData.StringVal = yytext; return OPTION; }
|
||||
{Integer} { ConfigLexerData.IntegerVal = IntToVal(yytext); return INTEGER; }
|
||||
{String} { yytext[yyleng-1] = 0; // nuke end quote
|
||||
ConfigLexerData.StringVal = yytext+1; // Nuke start quote
|
||||
return STRING;
|
||||
}
|
||||
|
||||
%%
|
@ -13,391 +13,282 @@
|
||||
//===------------------------------------------------------------------------===
|
||||
|
||||
#include "ConfigData.h"
|
||||
#include "ConfigLexer.h"
|
||||
#include "CompilerDriver.h"
|
||||
#include "Support/StringExtras.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
extern int ::Configlex();
|
||||
|
||||
namespace llvm {
|
||||
ConfigLexerInfo ConfigLexerData;
|
||||
InputProvider* ConfigLexerInput = 0;
|
||||
unsigned ConfigLexerLine = 1;
|
||||
|
||||
InputProvider::~InputProvider() {}
|
||||
void InputProvider::error(const std::string& msg) {
|
||||
std::cerr << name << ":" << ConfigLexerLine << ": Error: " << msg << "\n";
|
||||
errCount++;
|
||||
}
|
||||
|
||||
void InputProvider::checkErrors() {
|
||||
if (errCount > 0) {
|
||||
std::cerr << name << " had " << errCount << " errors. Terminating.\n";
|
||||
exit(errCount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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@"
|
||||
};
|
||||
class FileInputProvider : public InputProvider {
|
||||
public:
|
||||
FileInputProvider(const std::string & fname)
|
||||
: InputProvider(fname)
|
||||
, F(fname.c_str()) {
|
||||
ConfigLexerInput = this;
|
||||
}
|
||||
virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
|
||||
virtual unsigned read(char *buffer, unsigned max_size) {
|
||||
if (F.good()) {
|
||||
F.read(buffer,max_size);
|
||||
if ( F.gcount() ) return F.gcount() - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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@"
|
||||
};
|
||||
bool okay() { return F.good(); }
|
||||
private:
|
||||
std::ifstream F;
|
||||
};
|
||||
|
||||
class InputProvider {
|
||||
public:
|
||||
virtual bool getLine(std::string& line) = 0;
|
||||
virtual void error(const std::string& msg) = 0;
|
||||
virtual bool errorOccurred() = 0;
|
||||
};
|
||||
struct ParseContext
|
||||
{
|
||||
int token;
|
||||
InputProvider* provider;
|
||||
CompilerDriver::ConfigData* confDat;
|
||||
CompilerDriver::Action* action;
|
||||
|
||||
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;
|
||||
int next() { return token = Configlex(); }
|
||||
|
||||
bool next_is_real() {
|
||||
token = Configlex();
|
||||
return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
|
||||
}
|
||||
|
||||
virtual void error(const std::string& msg) {
|
||||
std::cerr << name << ":" << where << ": Error: " << msg << "\n";
|
||||
errCount++;
|
||||
void eatLineRemnant() {
|
||||
while (next_is_real()) ;
|
||||
}
|
||||
|
||||
virtual bool errorOccurred() { return errCount > 0; };
|
||||
void error(const std::string& msg, bool skip = true) {
|
||||
provider->error(msg);
|
||||
if (skip)
|
||||
eatLineRemnant();
|
||||
}
|
||||
|
||||
private:
|
||||
const char**TheData;
|
||||
size_t limit;
|
||||
size_t where;
|
||||
std::string name;
|
||||
size_t errCount;
|
||||
};
|
||||
std::string parseName() {
|
||||
std::string result;
|
||||
if (next() == EQUALS) {
|
||||
while (next_is_real()) {
|
||||
switch (token ) {
|
||||
case STRING :
|
||||
case OPTION :
|
||||
result += ConfigLexerData.StringVal + " ";
|
||||
break;
|
||||
default:
|
||||
error("Invalid name");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result.empty())
|
||||
error("Name exepected");
|
||||
else
|
||||
result.erase(result.size()-1,1);
|
||||
} else
|
||||
error("= expected");
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool recognize(const char*& p, const char*token) {
|
||||
while (*p == *token && *token != '\0')
|
||||
++token, p++;
|
||||
return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
|
||||
}
|
||||
bool parseBoolean() {
|
||||
bool result = true;
|
||||
if (next() == EQUALS) {
|
||||
if (next() == FALSETOK) {
|
||||
result = false;
|
||||
} else if (token != TRUETOK) {
|
||||
error("Expecting boolean value");
|
||||
return false;
|
||||
}
|
||||
if (next() != EOLTOK && token != 0) {
|
||||
error("Extraneous tokens after boolean");
|
||||
}
|
||||
}
|
||||
else
|
||||
error("Expecting '='");
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void parseLang() {
|
||||
if ( next() == NAME ) {
|
||||
confDat->langName = parseName();
|
||||
} else if (token == TRANSLATOR) {
|
||||
switch (next()) {
|
||||
case PREPROCESSES:
|
||||
confDat->TranslatorPreprocesses = parseBoolean();
|
||||
break;
|
||||
case OPTIMIZES:
|
||||
confDat->TranslatorOptimizes = parseBoolean();
|
||||
break;
|
||||
case GROKS_DASH_O:
|
||||
confDat->TranslatorGroksDashO = parseBoolean();
|
||||
break;
|
||||
default:
|
||||
error("Invalid lang.translator identifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (token == PREPROCESSOR) {
|
||||
if (next() == NEEDED)
|
||||
confDat->PreprocessorNeeded = parseBoolean();
|
||||
}
|
||||
else {
|
||||
error("Expecting valid identifier after 'lang.'");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
void parseCommand(CompilerDriver::Action& action) {
|
||||
if (next() == EQUALS) {
|
||||
next();
|
||||
if (token == EOLTOK) {
|
||||
// no value (valid)
|
||||
action.program.clear();
|
||||
action.args.clear();
|
||||
action.inputAt = 0;
|
||||
action.outputAt = 0;
|
||||
} else {
|
||||
if (token == STRING || token == OPTION) {
|
||||
action.program = ConfigLexerData.StringVal;
|
||||
} 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;
|
||||
}
|
||||
error("Expecting a program name");
|
||||
}
|
||||
while (next_is_real()) {
|
||||
if (token == STRING || token == OPTION)
|
||||
action.args.push_back(ConfigLexerData.StringVal);
|
||||
else if (token == IN_SUBST) {
|
||||
action.inputAt = action.args.size();
|
||||
action.args.push_back("in");
|
||||
} else if (token == OUT_SUBST) {
|
||||
action.outputAt = action.args.size();
|
||||
action.args.push_back("out");
|
||||
} else
|
||||
error("Expecting a program argument", false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default :
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void parsePreProcessor() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->PreProcessor);
|
||||
}
|
||||
|
||||
void parseTranslator() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Translator);
|
||||
}
|
||||
|
||||
void parseOptimizer() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Optimizer);
|
||||
}
|
||||
|
||||
void parseAssembler() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Assembler);
|
||||
}
|
||||
|
||||
void parseLinker() {
|
||||
if (next() != COMMAND) {
|
||||
error("Expecting 'command'");
|
||||
return;
|
||||
}
|
||||
parseCommand(confDat->Linker);
|
||||
}
|
||||
|
||||
void parseAssignment() {
|
||||
switch (token) {
|
||||
case LANG: return parseLang();
|
||||
case PREPROCESSOR: return parsePreProcessor();
|
||||
case TRANSLATOR: return parseTranslator();
|
||||
case OPTIMIZER: return parseOptimizer();
|
||||
case ASSEMBLER: return parseAssembler();
|
||||
case LINKER: return parseLinker();
|
||||
case EOLTOK: break; // just ignore
|
||||
case ERRORTOK:
|
||||
default:
|
||||
error("Invalid top level configuration item identifier");
|
||||
}
|
||||
}
|
||||
|
||||
void parseFile() {
|
||||
while ( next() != 0 ) {
|
||||
parseAssignment();
|
||||
}
|
||||
provider->checkErrors();
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
|
||||
ParseContext ctxt;
|
||||
ctxt.token = 0;
|
||||
ctxt.provider = &provider;
|
||||
ctxt.confDat = &confDat;
|
||||
ctxt.action = 0;
|
||||
ctxt.parseFile();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
|
||||
CompilerDriver::ConfigData* result = 0;
|
||||
if (configDir.empty()) {
|
||||
FileInputProvider fip( std::string("/etc/llvm/") + ftype );
|
||||
if (!fip.okay()) {
|
||||
fip.error("Configuration for '" + ftype + "' is not available.");
|
||||
fip.checkErrors();
|
||||
}
|
||||
else {
|
||||
result = new CompilerDriver::ConfigData();
|
||||
ParseConfigData(fip,*result);
|
||||
}
|
||||
} else {
|
||||
FileInputProvider fip( configDir + "/" + ftype );
|
||||
if (!fip.okay()) {
|
||||
fip.error("Configuration for '" + ftype + "' is not available.");
|
||||
fip.checkErrors();
|
||||
}
|
||||
else {
|
||||
result = new CompilerDriver::ConfigData();
|
||||
ParseConfigData(fip,*result);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
|
||||
|
@ -42,6 +42,9 @@ namespace llvm {
|
||||
/// @brief Allow the configuration directory to be set
|
||||
virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
|
||||
|
||||
private:
|
||||
CompilerDriver::ConfigData* ReadConfigData(const std::string& ftype);
|
||||
|
||||
/// @}
|
||||
/// @name Data
|
||||
/// @{
|
||||
|
@ -207,6 +207,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
// Construct the ConfigDataProvider object
|
||||
LLVMC_ConfigDataProvider Provider;
|
||||
Provider.setConfigDir(ConfigDir);
|
||||
|
||||
// Construct the CompilerDriver object
|
||||
CompilerDriver CD(Provider);
|
||||
|
Loading…
Reference in New Issue
Block a user