1 //===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by Reid Spencer and is distributed under the
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the parsing of configuration files for the LLVM Compiler
13 //===------------------------------------------------------------------------===
15 #include "ConfigData.h"
16 #include "ConfigLexer.h"
17 #include "CompilerDriver.h"
18 #include "Support/StringExtras.h"
24 extern int ::Configlineno;
27 ConfigLexerInfo ConfigLexerData;
28 InputProvider* ConfigLexerInput = 0;
30 InputProvider::~InputProvider() {}
31 void InputProvider::error(const std::string& msg) {
32 std::cerr << name << ":" << Configlineno << ": Error: " << msg << "\n";
36 void InputProvider::checkErrors() {
38 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
47 class FileInputProvider : public InputProvider {
49 FileInputProvider(const std::string & fname)
50 : InputProvider(fname)
52 ConfigLexerInput = this;
54 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
55 virtual unsigned read(char *buffer, unsigned max_size) {
57 F.read(buffer,max_size);
58 if ( F.gcount() ) return F.gcount() - 1;
63 bool okay() { return F.good(); }
70 ConfigLexerTokens token;
71 InputProvider* provider;
72 CompilerDriver::ConfigData* confDat;
73 CompilerDriver::Action* action;
75 int next() { return token = Configlex(); }
79 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
82 void eatLineRemnant() {
83 while (next_is_real()) ;
86 void error(const std::string& msg, bool skip = true) {
92 std::string parseName() {
94 if (next() == EQUALS) {
95 while (next_is_real()) {
99 result += ConfigLexerData.StringVal + " ";
102 error("Invalid name");
107 error("Name exepected");
109 result.erase(result.size()-1,1);
115 bool parseBoolean() {
117 if (next() == EQUALS) {
118 if (next() == FALSETOK) {
120 } else if (token != TRUETOK) {
121 error("Expecting boolean value");
124 if (next() != EOLTOK && token != 0) {
125 error("Extraneous tokens after boolean");
129 error("Expecting '='");
133 void parseOptionList(CompilerDriver::StringVector& optList ) {
134 while (next_is_real()) {
135 if (token == STRING || token == OPTION)
136 optList.push_back(ConfigLexerData.StringVal);
138 error("Expecting a program option", false);
147 confDat->langName = parseName();
150 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
153 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
156 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
159 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
163 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
166 error("Expecting 'name' or 'optN' after 'lang.'");
171 void parseCommand(CompilerDriver::Action& action) {
172 if (next() == EQUALS) {
173 if (next() == EOLTOK) {
175 action.program.clear();
180 if (token == STRING || token == OPTION) {
181 action.program = ConfigLexerData.StringVal;
183 error("Expecting a program name");
185 while (next_is_real()) {
186 if (token == STRING || token == OPTION) {
187 action.args.push_back(ConfigLexerData.StringVal);
188 } else if (token == IN_SUBST) {
189 action.inputAt = action.args.size();
190 action.args.push_back("@in@");
191 } else if (token == OUT_SUBST) {
192 action.outputAt = action.args.size();
193 action.args.push_back("@out@");
195 error("Expecting a program argument", false);
203 void parsePreprocessor() {
206 parseCommand(confDat->PreProcessor);
210 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
212 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
215 error("Expecting 'command' or 'required'");
220 void parseTranslator() {
223 parseCommand(confDat->Translator);
227 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
229 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
233 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
235 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
239 confDat->Translator.set(CompilerDriver::OPTIMIZES_FLAG);
241 confDat->Translator.clear(CompilerDriver::OPTIMIZES_FLAG);
245 confDat->Translator.set(CompilerDriver::GROKS_DASH_O_FLAG);
247 confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG);
251 confDat->Translator.set(CompilerDriver::GROKS_O10N_FLAG);
253 confDat->Translator.clear(CompilerDriver::GROKS_O10N_FLAG);
256 error("Expecting 'command', 'required', 'preprocesses', "
257 "'groks_dash_O' or 'optimizes'");
262 void parseOptimizer() {
265 parseCommand(confDat->Optimizer);
269 confDat->Optimizer.set(CompilerDriver::GROKS_DASH_O_FLAG);
271 confDat->Optimizer.clear(CompilerDriver::GROKS_DASH_O_FLAG);
275 confDat->Optimizer.set(CompilerDriver::GROKS_O10N_FLAG);
277 confDat->Optimizer.clear(CompilerDriver::GROKS_O10N_FLAG);
280 error("Expecting 'command' or 'groks_dash_O'");
285 void parseAssembler() {
288 parseCommand(confDat->Assembler);
291 error("Expecting 'command'");
299 parseCommand(confDat->Linker);
303 confDat->Linker.set(CompilerDriver::GROKS_DASH_O_FLAG);
305 confDat->Linker.clear(CompilerDriver::GROKS_DASH_O_FLAG);
309 confDat->Linker.set(CompilerDriver::GROKS_O10N_FLAG);
311 confDat->Linker.clear(CompilerDriver::GROKS_O10N_FLAG);
314 error("Expecting 'command'");
319 void parseAssignment() {
321 case LANG: parseLang(); break;
322 case PREPROCESSOR: parsePreprocessor(); break;
323 case TRANSLATOR: parseTranslator(); break;
324 case OPTIMIZER: parseOptimizer(); break;
325 case ASSEMBLER: parseAssembler(); break;
326 case LINKER: parseLinker(); break;
327 case EOLTOK: break; // just ignore
330 error("Invalid top level configuration item");
336 while ( next() != EOFTOK ) {
337 if (token == ERRORTOK)
338 error("Invalid token");
339 else if (token != EOLTOK)
342 provider->checkErrors();
347 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
350 p.provider = &provider;
351 p.confDat = &confDat;
357 CompilerDriver::ConfigData*
358 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
359 CompilerDriver::ConfigData* result = 0;
360 if (configDir.empty()) {
361 FileInputProvider fip( std::string("/etc/llvm/") + ftype );
363 fip.error("Configuration for '" + ftype + "' is not available.");
367 result = new CompilerDriver::ConfigData();
368 ParseConfigData(fip,*result);
371 FileInputProvider fip( configDir + "/" + ftype );
373 fip.error("Configuration for '" + ftype + "' is not available.");
377 result = new CompilerDriver::ConfigData();
378 ParseConfigData(fip,*result);
384 LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
388 Configurations.clear();
391 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
393 ConfigDataMap::iterator cIt = Configurations.begin();
394 while (cIt != Configurations.end()) {
395 CompilerDriver::ConfigData* cd = cIt->second;
399 Configurations.clear();
402 CompilerDriver::ConfigData*
403 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
404 CompilerDriver::ConfigData* result = 0;
405 if (!Configurations.empty()) {
406 ConfigDataMap::iterator cIt = Configurations.find(filetype);
407 if ( cIt != Configurations.end() ) {
408 // We found one in the case, return it.
409 result = cIt->second;
413 // The configuration data doesn't exist, we have to go read it.
414 result = ReadConfigData(filetype);
415 // If we got one, cache it
417 Configurations.insert(std::make_pair(filetype,result));
419 return result; // Might return 0
422 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab