blob: 94949c405de98f0fc323866628f4874d0fdc2a47 [file] [log] [blame]
Reid Spencer2594c9a2004-08-13 20:21:22 +00001//===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
2//
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
15#include "ConfigData.h"
16#include "CompilerDriver.h"
17#include "Support/StringExtras.h"
18#include <iostream>
19
20using namespace llvm;
21
22namespace {
23
24// This array of strings provides the input for ".ll" files (LLVM Assembly)
25// to the configuration file parser. This data is just "built-in" to
26// llvmc so it doesn't have to be read from a configuration file.
27static const char* LL_Data[] = {
28 "lang.name=LLVM Assembly",
29 "lang.translator.preprocesses=false",
30 "lang.translator.optimizes=No",
31 "lang.translator.groks_dash_O=No",
32 "lang.preprocessor.needed=0",
33 "preprocessor.prog=",
34 "preprocessor.args=",
35 "translator.prog=llvm-as",
36 "translator.args=@in@ -o @out@",
37 "optimizer.prog=opt",
38 "optimizer.args=@in@ -o @out@",
39 "assembler.prog=llc",
40 "assembler.args=@in@ -o @out@",
41 "linker.prog=llvm-link",
42 "linker.args=@in@ -o @out@"
43};
44
45// This array of strings provides the input for ".st" files (Stacker).
46static const char* ST_Data[] = {
47 "lang.name=Stacker",
48 "lang.translator.preprocesses=false",
49 "lang.translator.optimizes=true",
50 "lang.translator.groks_dash_O=0",
51 "lang.preprocessor.needed=0",
52 "preprocessor.prog=cp",
53 "preprocessor.args=@in@ @out@",
54 "translator.prog=stkrc",
55 "translator.args=@in@ -o @out@ -S 2048",
56 "optimizer.prog=opt",
57 "optimizer.args=@in@ -o @out@",
58 "assembler.prog=llc",
59 "assembler.args=@in@ -o @out@",
60 "linker.prog=llvm-link",
61 "linker.args=@in@ -o @out@"
62};
63
64class InputProvider {
65 public:
66 virtual bool getLine(std::string& line) = 0;
67 virtual void error(const std::string& msg) = 0;
68 virtual bool errorOccurred() = 0;
69};
70
71class StaticInputProvider : public InputProvider {
72 public:
73 StaticInputProvider(const char *data[], size_t count,
74 const std::string& nam) {
75 TheData = data;
76 limit = count;
77 where = 0;
78 name = nam;
79 errCount = 0;
80 }
81 virtual ~StaticInputProvider() {}
82 virtual bool getLine(std::string& line) {
83 if ( where >= limit ) return false;
84 line = TheData[where++];
85 return true;
86 }
87
88 virtual void error(const std::string& msg) {
89 std::cerr << name << ":" << where << ": Error: " << msg << "\n";
90 errCount++;
91 }
92
93 virtual bool errorOccurred() { return errCount > 0; };
94
95 private:
96 const char**TheData;
97 size_t limit;
98 size_t where;
99 std::string name;
100 size_t errCount;
101};
102
103inline bool recognize(const char*& p, const char*token) {
104 while (*p == *token && *token != '\0')
105 ++token, p++;
106 return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
107}
108
109inline bool getBoolean(const std::string& value) {
110 switch (value[0]) {
111 case 't':
112 case 'T':
113 case '1':
114 case 'y':
115 case 'Y':
116 return true;
117 default :
118 return false;
119 }
120 return false;
121}
122
123inline void skipWhitespace( size_t& pos, const std::string& line ) {
124 while (pos < line.size() && (
125 line[pos] == ' ' || // Space
126 line[pos] == '\t' || // Horizontal Tab
127 line[pos] == '\n' || // New Line
128 line[pos] == '\v' || // Vertical Tab
129 line[pos] == '\f' || // Form Feed
130 line[pos] == '\r') // Carriate Return
131 )
132 pos++;
133}
134
135inline void parseArgs(CompilerDriver::Action& pat,
136 const std::string& value,
137 InputProvider& provider )
138{
139 const char* p = value.c_str();
140 const char* argStart = p;
141 while (*p != '\0') {
142 switch (*p) {
143 case ' ':
144 if (argStart != p)
145 pat.args.push_back(std::string(argStart, p-argStart));
146 argStart = ++p;
147 break;
148 case '@' :
149 {
150 if (argStart != p)
151 pat.args.push_back(std::string(argStart,p-argStart));
152 const char* token = ++p;
153 while (*p != '@' && *p != 0)
154 p++;
155 if ( *p != '@' ) {
156 provider.error("Unterminated substitution token");
157 return;
158 } else {
159 p++;
160 bool legal = false;
161 switch (token[0]) {
162 case 'i':
163 if (token[1] == 'n' && token[2] == '@' ) {
164 pat.inputAt = pat.args.size();
165 pat.args.push_back("in");
166 legal = true;
167 argStart = p;
168 }
169 break;
170 case 'o':
171 if (token[1] == 'u' && token[2] == 't' && token[3] == '@') {
172 pat.outputAt = pat.args.size();
173 pat.args.push_back("out");
174 legal = true;
175 argStart = p;
176 }
177 break;
178 default:
179 break;
180 }
181 if (!legal) {
182 provider.error("Invalid substitution token");
183 return;
184 }
185 }
186 }
187 break;
188 default :
189 p++;
190 break;
191 }
192 }
193}
194
195CompilerDriver::ConfigData*
196ParseConfigData(InputProvider& provider) {
197 std::string line;
198 CompilerDriver::ConfigData data;
199 while ( provider.getLine(line) ) {
200 // Check line length first
201 size_t lineLen = line.size();
202 if (lineLen > 4096)
203 provider.error("length of input line (" + utostr(lineLen) +
204 ") is too long");
205
206 // First, skip whitespace
207 size_t stPos = 0;
208 skipWhitespace(stPos, line);
209
210 // See if there's a hash mark. It and everything after it is
211 // ignored so lets delete that now.
212 size_t hashPos = line.find('#');
213 if (hashPos != std::string::npos)
214 line.erase(hashPos);
215
216 // Make sure we have something left to parse
217 if (line.size() == 0)
218 continue; // ignore full-line comment or whitespace line
219
220 // Find the equals sign
221 size_t eqPos = line.find('=');
222 if (eqPos == std::string::npos)
223 provider.error("Configuration directive is missing an =");
224
225 // extract the item name
226 std::string name(line, stPos, eqPos-stPos);
227
228 // directives without names are illegal
229 if (name.empty())
230 provider.error("Configuration directive name is empty");
231
232 // Skip whitespace in the value
233 size_t valPos = eqPos + 1;
234 skipWhitespace(valPos, line);
235
236 // Skip white space at end of value
237 size_t endPos = line.length() - 1;
238 while (line[endPos] == ' ')
239 endPos--;
240
241 // extract the item value
242 std::string value(line, valPos, endPos-valPos+1);
243
244 // Get the configuration item as a char pointer
245 const char*p = name.c_str();
246
247 // Indicate we haven't found an invalid item yet.
248 bool invalidItem = false;
249
250 // Parse the contents by examining first character and
251 // using the recognize function strategically
252 switch (*p++) {
253 case 'l' :
254 // could it be "lang."
255 if (*p == 'a') { // "lang." ?
256 if (recognize(p,"ang")) {
257 p++;
258 switch (*p++) {
259 case 'n':
260 if (recognize(p,"ame"))
261 data.langName = value;
262 else
263 invalidItem = true;
264 break;
265 case 't':
266 if (recognize(p,"ranslator")) {
267 p++;
268 if (recognize(p,"preprocesses"))
269 data.TranslatorPreprocesses = getBoolean(value);
270 else if (recognize(p, "optimizes"))
271 data.TranslatorOptimizes = getBoolean(value);
272 else if (recognize(p, "groks_dash_O"))
273 data.TranslatorGroksDashO = getBoolean(value);
274 else
275 invalidItem = true;
276 }
277 else
278 invalidItem = true;
279 break;
280 case 'p':
281 if (recognize(p,"reprocessor")) {
282 p++;
283 if (recognize(p,"needed")) {
284 data.PreprocessorNeeded = getBoolean(value);
285 } else
286 invalidItem = true;
287 }
288 else
289 invalidItem = true;
290 break;
291
292 default:
293 invalidItem = true;
294 break;
295 }
296 }
297 } else if (*p == 'i') { // "linker." ?
298 if (recognize(p,"inker")) {
299 p++;
300 if (recognize(p,"prog"))
301 data.Linker.program = value;
302 else if (recognize(p,"args"))
303 parseArgs(data.Linker,value,provider);
304 else
305 invalidItem = true;
306 }
307 else
308 invalidItem = true;
309 } else {
310 invalidItem = true;
311 }
312 break;
313
314 case 'p' :
315 if (*p == 'r') { // "preprocessor." ?
316 if (recognize(p, "reprocessor")) {
317 p++;
318 if (recognize(p,"prog"))
319 data.PreProcessor.program = value;
320 else if (recognize(p,"args"))
321 parseArgs(data.PreProcessor,value,provider);
322 else
323 invalidItem = true;
324 } else
325 invalidItem = true;
326 } else {
327 invalidItem = true;
328 }
329 break;
330
331 case 't' :
332 if (*p == 'r') { // "translator." ?
333 if (recognize(p, "ranslator")) {
334 p++;
335 if (recognize(p,"prog"))
336 data.Translator.program = value;
337 else if (recognize(p,"args"))
338 parseArgs(data.Translator,value,provider);
339 else
340 invalidItem = true;
341 } else
342 invalidItem = true;
343 } else {
344 invalidItem = true;
345 }
346 break;
347
348 case 'o' :
349 if (*p == 'p') { // "optimizer." ?
350 if (recognize(p, "ptimizer")) {
351 p++;
352 if (recognize(p,"prog"))
353 data.Optimizer.program = value;
354 else if (recognize(p,"args"))
355 parseArgs(data.Optimizer,value,provider);
356 else
357 invalidItem = true;
358 } else
359 invalidItem = true;
360 } else {
361 invalidItem = true;
362 }
363 break;
364 case 'a' :
365 if (*p == 's') { // "assembler." ?
366 if (recognize(p, "ssembler")) {
367 p++;
368 if (recognize(p,"prog"))
369 data.Assembler.program = value;
370 else if (recognize(p,"args"))
371 parseArgs(data.Assembler,value,provider);
372 else
373 invalidItem = true;
374 } else
375 invalidItem = true;
376 } else {
377 invalidItem = true;
378 }
379 break;
380 }
381 if (invalidItem)
382 provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos));
383 }
384 return new CompilerDriver::ConfigData(data);
385}
386
387CompilerDriver::ConfigData*
388ReadConfigData(const std::string& ftype) {
389 if ( ftype == "ll" ) {
390 StaticInputProvider sip(LL_Data, sizeof(LL_Data)/sizeof(LL_Data[0]),
391 "LLVM Assembly (internal)");
392 return ParseConfigData(sip);
393 } else if (ftype == "st") {
394 StaticInputProvider sip(ST_Data, sizeof(ST_Data)/sizeof(ST_Data[0]),
395 "Stacker (internal)");
396 return ParseConfigData(sip);
397 }
398 return 0;
399}
400
401}
402
403LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
404 : Configurations()
405 , configDir()
406{
407 Configurations.clear();
408}
409
410LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
411{
412 ConfigDataMap::iterator cIt = Configurations.begin();
413 while (cIt != Configurations.end()) {
414 CompilerDriver::ConfigData* cd = cIt->second;
415 ++cIt;
416 delete cd;
417 }
418 Configurations.clear();
419}
420
421CompilerDriver::ConfigData*
422LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
423 CompilerDriver::ConfigData* result = 0;
424 if (!Configurations.empty()) {
425 ConfigDataMap::iterator cIt = Configurations.find(filetype);
426 if ( cIt != Configurations.end() ) {
427 // We found one in the case, return it.
428 result = cIt->second;
429 }
430 }
431 if (result == 0) {
432 // The configuration data doesn't exist, we have to go read it.
433 result = ReadConfigData(filetype);
434 // If we got one, cache it
435 if ( result != 0 )
436 Configurations.insert(std::make_pair(filetype,result));
437 }
438 return result; // Might return 0
439}
440
441// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab