blob: 1463ecaa7eea1b23e6a8c1f9c1463f4e4fe7ac64 [file] [log] [blame]
Reid Spencercbabe7f2004-08-19 21:17:53 +00001//===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
Reid Spencer2594c9a2004-08-13 20:21:22 +00002//
3// The LLVM Compiler Infrastructure
4//
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.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the parsing of configuration files for the LLVM Compiler
11// Driver (llvmc).
12//
13//===------------------------------------------------------------------------===
14
Reid Spencerf51a87c2004-08-19 21:52:49 +000015#include "Configuration.h"
Reid Spencer68fb37a2004-08-14 09:37:15 +000016#include "ConfigLexer.h"
Reid Spencer2594c9a2004-08-13 20:21:22 +000017#include "CompilerDriver.h"
Reid Spencerbae68252004-08-19 04:49:47 +000018#include "Support/CommandLine.h"
Reid Spencer2594c9a2004-08-13 20:21:22 +000019#include "Support/StringExtras.h"
20#include <iostream>
Reid Spencer68fb37a2004-08-14 09:37:15 +000021#include <fstream>
Reid Spencer2594c9a2004-08-13 20:21:22 +000022
23using namespace llvm;
24
Reid Spencer68fb37a2004-08-14 09:37:15 +000025namespace llvm {
Reid Spencerbae68252004-08-19 04:49:47 +000026 ConfigLexerInfo ConfigLexerState;
Reid Spencer68fb37a2004-08-14 09:37:15 +000027 InputProvider* ConfigLexerInput = 0;
Reid Spencer68fb37a2004-08-14 09:37:15 +000028
29 InputProvider::~InputProvider() {}
30 void InputProvider::error(const std::string& msg) {
Reid Spencerbae68252004-08-19 04:49:47 +000031 std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
32 msg << "\n";
Reid Spencer68fb37a2004-08-14 09:37:15 +000033 errCount++;
34 }
35
36 void InputProvider::checkErrors() {
37 if (errCount > 0) {
38 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
39 exit(errCount);
40 }
41 }
42
43}
44
Reid Spencer2594c9a2004-08-13 20:21:22 +000045namespace {
46
Reid Spencer68fb37a2004-08-14 09:37:15 +000047 class FileInputProvider : public InputProvider {
48 public:
49 FileInputProvider(const std::string & fname)
50 : InputProvider(fname)
51 , F(fname.c_str()) {
52 ConfigLexerInput = this;
53 }
54 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
55 virtual unsigned read(char *buffer, unsigned max_size) {
56 if (F.good()) {
57 F.read(buffer,max_size);
58 if ( F.gcount() ) return F.gcount() - 1;
59 }
60 return 0;
61 }
Reid Spencer2594c9a2004-08-13 20:21:22 +000062
Reid Spencer68fb37a2004-08-14 09:37:15 +000063 bool okay() { return F.good(); }
64 private:
65 std::ifstream F;
66 };
Reid Spencer2594c9a2004-08-13 20:21:22 +000067
Reid Spencerbae68252004-08-19 04:49:47 +000068 cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden, cl::init(false),
69 cl::desc("Dump lexical tokens (debug use only)."));
70
Reid Spencerbf437722004-08-15 08:19:46 +000071 struct Parser
Reid Spencer68fb37a2004-08-14 09:37:15 +000072 {
Reid Spencerbae68252004-08-19 04:49:47 +000073 Parser() {
74 token = EOFTOK;
75 provider = 0;
76 confDat = 0;
77 ConfigLexerState.lineNum = 1;
78 ConfigLexerState.in_value = false;
79 ConfigLexerState.StringVal.clear();
80 ConfigLexerState.IntegerVal = 0;
81 };
82
Reid Spencerbf437722004-08-15 08:19:46 +000083 ConfigLexerTokens token;
Reid Spencer68fb37a2004-08-14 09:37:15 +000084 InputProvider* provider;
85 CompilerDriver::ConfigData* confDat;
Reid Spencer2594c9a2004-08-13 20:21:22 +000086
Reid Spencerbae68252004-08-19 04:49:47 +000087 int next() {
88 token = Configlex();
89 if (DumpTokens)
90 std::cerr << token << "\n";
91 return token;
92 }
Reid Spencer68fb37a2004-08-14 09:37:15 +000093
94 bool next_is_real() {
Reid Spencerbae68252004-08-19 04:49:47 +000095 next();
Reid Spencer68fb37a2004-08-14 09:37:15 +000096 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
Reid Spencer2594c9a2004-08-13 20:21:22 +000097 }
98
Reid Spencer68fb37a2004-08-14 09:37:15 +000099 void eatLineRemnant() {
100 while (next_is_real()) ;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000101 }
102
Reid Spencer68fb37a2004-08-14 09:37:15 +0000103 void error(const std::string& msg, bool skip = true) {
104 provider->error(msg);
105 if (skip)
106 eatLineRemnant();
107 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000108
Reid Spencer68fb37a2004-08-14 09:37:15 +0000109 std::string parseName() {
110 std::string result;
111 if (next() == EQUALS) {
112 while (next_is_real()) {
113 switch (token ) {
114 case STRING :
115 case OPTION :
Reid Spencerbae68252004-08-19 04:49:47 +0000116 result += ConfigLexerState.StringVal + " ";
Reid Spencer68fb37a2004-08-14 09:37:15 +0000117 break;
118 default:
119 error("Invalid name");
120 break;
121 }
122 }
123 if (result.empty())
124 error("Name exepected");
125 else
126 result.erase(result.size()-1,1);
127 } else
128 error("= expected");
129 return result;
130 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000131
Reid Spencer68fb37a2004-08-14 09:37:15 +0000132 bool parseBoolean() {
133 bool result = true;
134 if (next() == EQUALS) {
135 if (next() == FALSETOK) {
136 result = false;
137 } else if (token != TRUETOK) {
138 error("Expecting boolean value");
139 return false;
140 }
141 if (next() != EOLTOK && token != 0) {
142 error("Extraneous tokens after boolean");
143 }
144 }
145 else
146 error("Expecting '='");
147 return result;
148 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000149
Reid Spencerbae68252004-08-19 04:49:47 +0000150 bool parseSubstitution(CompilerDriver::StringVector& optList) {
151 switch (token) {
152 case IN_SUBST: optList.push_back("@in@"); break;
153 case OUT_SUBST: optList.push_back("@out@"); break;
154 case TIME_SUBST: optList.push_back("@time@"); break;
155 case STATS_SUBST: optList.push_back("@stats@"); break;
156 case OPT_SUBST: optList.push_back("@opt@"); break;
157 case TARGET_SUBST: optList.push_back("@target@"); break;
158 default:
159 return false;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000160 }
Reid Spencerbae68252004-08-19 04:49:47 +0000161 return true;
162 }
163
164 void parseOptionList(CompilerDriver::StringVector& optList ) {
165 if (next() == EQUALS) {
166 while (next_is_real()) {
167 if (token == STRING || token == OPTION)
168 optList.push_back(ConfigLexerState.StringVal);
169 else if (!parseSubstitution(optList)) {
170 error("Expecting a program argument or substitution", false);
171 break;
172 }
173 }
174 } else
175 error("Expecting '='");
Reid Spencerbf437722004-08-15 08:19:46 +0000176 }
177
178 void parseLang() {
179 switch (next() ) {
180 case NAME:
181 confDat->langName = parseName();
182 break;
183 case OPT1:
184 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
185 break;
186 case OPT2:
187 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
188 break;
189 case OPT3:
190 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
191 break;
192 case OPT4:
193 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
194 break;
195 case OPT5:
196 parseOptionList(
197 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
198 break;
199 default:
200 error("Expecting 'name' or 'optN' after 'lang.'");
201 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000202 }
203 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000204
Reid Spencer68fb37a2004-08-14 09:37:15 +0000205 void parseCommand(CompilerDriver::Action& action) {
206 if (next() == EQUALS) {
Reid Spencerbf437722004-08-15 08:19:46 +0000207 if (next() == EOLTOK) {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000208 // no value (valid)
209 action.program.clear();
210 action.args.clear();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000211 } else {
212 if (token == STRING || token == OPTION) {
Reid Spencerbae68252004-08-19 04:49:47 +0000213 action.program = ConfigLexerState.StringVal;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000214 } else {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000215 error("Expecting a program name");
216 }
217 while (next_is_real()) {
Reid Spencerbf437722004-08-15 08:19:46 +0000218 if (token == STRING || token == OPTION) {
Reid Spencerbae68252004-08-19 04:49:47 +0000219 action.args.push_back(ConfigLexerState.StringVal);
220 } else if (!parseSubstitution(action.args)) {
221 error("Expecting a program argument or substitution", false);
Reid Spencerbf437722004-08-15 08:19:46 +0000222 break;
223 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000224 }
225 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000226 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000227 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000228
Reid Spencerbf437722004-08-15 08:19:46 +0000229 void parsePreprocessor() {
230 switch (next()) {
231 case COMMAND:
232 parseCommand(confDat->PreProcessor);
233 break;
234 case REQUIRED:
235 if (parseBoolean())
236 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
237 else
238 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
239 break;
240 default:
241 error("Expecting 'command' or 'required'");
242 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000243 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000244 }
245
246 void parseTranslator() {
Reid Spencerbf437722004-08-15 08:19:46 +0000247 switch (next()) {
248 case COMMAND:
249 parseCommand(confDat->Translator);
250 break;
251 case REQUIRED:
252 if (parseBoolean())
253 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
254 else
255 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
256 break;
257 case PREPROCESSES:
258 if (parseBoolean())
259 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
260 else
261 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
262 break;
263 case OPTIMIZES:
264 if (parseBoolean())
265 confDat->Translator.set(CompilerDriver::OPTIMIZES_FLAG);
266 else
267 confDat->Translator.clear(CompilerDriver::OPTIMIZES_FLAG);
268 break;
269 case GROKS_DASH_O:
270 if (parseBoolean())
271 confDat->Translator.set(CompilerDriver::GROKS_DASH_O_FLAG);
272 else
273 confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG);
274 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000275 case OUTPUT_IS_ASM:
Reid Spencerbf437722004-08-15 08:19:46 +0000276 if (parseBoolean())
Reid Spencerbae68252004-08-19 04:49:47 +0000277 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000278 else
Reid Spencerbae68252004-08-19 04:49:47 +0000279 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000280 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000281
Reid Spencerbf437722004-08-15 08:19:46 +0000282 default:
283 error("Expecting 'command', 'required', 'preprocesses', "
284 "'groks_dash_O' or 'optimizes'");
285 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000286 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000287 }
288
289 void parseOptimizer() {
Reid Spencerbf437722004-08-15 08:19:46 +0000290 switch (next()) {
291 case COMMAND:
292 parseCommand(confDat->Optimizer);
293 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000294 case PREPROCESSES:
295 if (parseBoolean())
296 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
297 else
298 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
299 break;
300 case TRANSLATES:
301 if (parseBoolean())
302 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
303 else
304 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
305 break;
Reid Spencerbf437722004-08-15 08:19:46 +0000306 case GROKS_DASH_O:
307 if (parseBoolean())
308 confDat->Optimizer.set(CompilerDriver::GROKS_DASH_O_FLAG);
309 else
310 confDat->Optimizer.clear(CompilerDriver::GROKS_DASH_O_FLAG);
311 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000312 case OUTPUT_IS_ASM:
Reid Spencerbf437722004-08-15 08:19:46 +0000313 if (parseBoolean())
Reid Spencerbae68252004-08-19 04:49:47 +0000314 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000315 else
Reid Spencerbae68252004-08-19 04:49:47 +0000316 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000317 break;
318 default:
319 error("Expecting 'command' or 'groks_dash_O'");
320 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000321 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000322 }
323
324 void parseAssembler() {
Reid Spencerbf437722004-08-15 08:19:46 +0000325 switch(next()) {
326 case COMMAND:
327 parseCommand(confDat->Assembler);
328 break;
329 default:
330 error("Expecting 'command'");
331 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000332 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000333 }
334
335 void parseLinker() {
Reid Spencerbf437722004-08-15 08:19:46 +0000336 switch(next()) {
337 case COMMAND:
338 parseCommand(confDat->Linker);
339 break;
340 case GROKS_DASH_O:
341 if (parseBoolean())
342 confDat->Linker.set(CompilerDriver::GROKS_DASH_O_FLAG);
343 else
344 confDat->Linker.clear(CompilerDriver::GROKS_DASH_O_FLAG);
345 break;
Reid Spencerbf437722004-08-15 08:19:46 +0000346 default:
347 error("Expecting 'command'");
348 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000349 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000350 }
351
352 void parseAssignment() {
353 switch (token) {
Reid Spencerbf437722004-08-15 08:19:46 +0000354 case LANG: parseLang(); break;
355 case PREPROCESSOR: parsePreprocessor(); break;
356 case TRANSLATOR: parseTranslator(); break;
357 case OPTIMIZER: parseOptimizer(); break;
358 case ASSEMBLER: parseAssembler(); break;
359 case LINKER: parseLinker(); break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000360 case EOLTOK: break; // just ignore
361 case ERRORTOK:
362 default:
Reid Spencerbf437722004-08-15 08:19:46 +0000363 error("Invalid top level configuration item");
364 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000365 }
366 }
367
368 void parseFile() {
Reid Spencerbf437722004-08-15 08:19:46 +0000369 while ( next() != EOFTOK ) {
370 if (token == ERRORTOK)
371 error("Invalid token");
372 else if (token != EOLTOK)
373 parseAssignment();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000374 }
375 provider->checkErrors();
376 }
377 };
378
379 void
380 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
Reid Spencerbf437722004-08-15 08:19:46 +0000381 Parser p;
382 p.token = EOFTOK;
383 p.provider = &provider;
384 p.confDat = &confDat;
Reid Spencerbf437722004-08-15 08:19:46 +0000385 p.parseFile();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000386 }
387}
388
389CompilerDriver::ConfigData*
Reid Spencer68fb37a2004-08-14 09:37:15 +0000390LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
391 CompilerDriver::ConfigData* result = 0;
392 if (configDir.empty()) {
393 FileInputProvider fip( std::string("/etc/llvm/") + ftype );
394 if (!fip.okay()) {
395 fip.error("Configuration for '" + ftype + "' is not available.");
396 fip.checkErrors();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000397 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000398 else {
399 result = new CompilerDriver::ConfigData();
400 ParseConfigData(fip,*result);
401 }
402 } else {
403 FileInputProvider fip( configDir + "/" + ftype );
404 if (!fip.okay()) {
405 fip.error("Configuration for '" + ftype + "' is not available.");
406 fip.checkErrors();
407 }
408 else {
409 result = new CompilerDriver::ConfigData();
410 ParseConfigData(fip,*result);
411 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000412 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000413 return result;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000414}
415
416LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
417 : Configurations()
418 , configDir()
419{
420 Configurations.clear();
421}
422
423LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
424{
425 ConfigDataMap::iterator cIt = Configurations.begin();
426 while (cIt != Configurations.end()) {
427 CompilerDriver::ConfigData* cd = cIt->second;
428 ++cIt;
429 delete cd;
430 }
431 Configurations.clear();
432}
433
434CompilerDriver::ConfigData*
435LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
436 CompilerDriver::ConfigData* result = 0;
437 if (!Configurations.empty()) {
438 ConfigDataMap::iterator cIt = Configurations.find(filetype);
439 if ( cIt != Configurations.end() ) {
440 // We found one in the case, return it.
441 result = cIt->second;
442 }
443 }
444 if (result == 0) {
445 // The configuration data doesn't exist, we have to go read it.
446 result = ReadConfigData(filetype);
447 // If we got one, cache it
448 if ( result != 0 )
449 Configurations.insert(std::make_pair(filetype,result));
450 }
451 return result; // Might return 0
452}
453
454// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab