]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/elftosb/elftosb2/ConversionController.cpp
Unified codebase for TX28, TX48, TX51, TX53
[karo-tx-uboot.git] / tools / elftosb / elftosb2 / ConversionController.cpp
1 /*
2  * File:        ConversionController.cpp
3  *
4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5  * See included license file for license details.
6  */
7
8 #include "ConversionController.h"
9 #include <stdexcept>
10 #include "EvalContext.h"
11 #include "ElftosbErrors.h"
12 #include "GlobMatcher.h"
13 #include "ExcludesListMatcher.h"
14 #include "BootImageGenerator.h"
15 #include "EncoreBootImageGenerator.h"
16 #include "Logging.h"
17 #include "OptionDictionary.h"
18 #include "format_string.h"
19 #include "SearchPath.h"
20 #include "DataSourceImager.h"
21 #include "IVTDataSource.h"
22 #include <algorithm>
23
24 //! Set to 1 to cause the ConversionController to print information about
25 //! the values that it processes (options, constants, etc.).
26 #define PRINT_VALUES 1
27
28 using namespace elftosb;
29
30 // Define the parser function prototype;
31 extern int yyparse(ElftosbLexer * lexer, CommandFileASTNode ** resultAST);
32
33 bool elftosb::g_enableHABSupport = false;
34
35 ConversionController::ConversionController()
36 :       OptionDictionary(),
37         m_commandFilePath(),
38         m_ast(),
39         m_defaultSource(0)
40 {
41         m_context.setSourceFileManager(this);
42 }
43
44 ConversionController::~ConversionController()
45 {
46         // clean up sources
47         source_map_t::iterator it = m_sources.begin();
48         for (; it != m_sources.end(); ++it)
49         {
50                 if (it->second)
51                 {
52                         delete it->second;
53                 }
54         }
55 }
56
57 void ConversionController::setCommandFilePath(const std::string & path)
58 {
59         m_commandFilePath = new std::string(path);
60 }
61
62 //! The paths provided to this method are added to an array and accessed with the
63 //! "extern(N)" notation in the command file. So the path provided in the third
64 //! call to addExternalFilePath() will be found with N=2 in the source definition.
65 void ConversionController::addExternalFilePath(const std::string & path)
66 {
67         m_externPaths.push_back(path);
68 }
69
70 bool ConversionController::hasSourceFile(const std::string & name)
71 {
72         return m_sources.find(name) != m_sources.end();
73 }
74
75 SourceFile * ConversionController::getSourceFile(const std::string & name)
76 {
77         if (!hasSourceFile(name))
78         {
79                 return NULL;
80         }
81         
82         return m_sources[name];
83 }
84
85 SourceFile * ConversionController::getDefaultSourceFile()
86 {
87         return m_defaultSource;
88 }
89
90 //! These steps are executed while running this method:
91 //!             - The command file is parsed into an abstract syntax tree.
92 //!             - The list of options is extracted.
93 //!             - Constant expressions are evaluated.
94 //!             - The list of source files is extracted and source file objects created.
95 //!             - Section definitions are extracted.
96 //!
97 //! This method does not produce any output. It processes the input files and
98 //! builds a representation of the output in memory. Use the generateOutput() method
99 //! to produce a BootImage object after this method returns.
100 //!
101 //! \note This method is \e not reentrant. And in fact, the whole class is not designed
102 //!             to be reentrant.
103 //!
104 //! \exception std::runtime_error Any number of problems will cause this exception to
105 //!             be thrown.
106 //!
107 //! \see parseCommandFile()
108 //! \see processOptions()
109 //! \see processConstants()
110 //! \see processSources()
111 //! \see processSections()
112 void ConversionController::run()
113 {
114 #if PRINT_VALUES
115         Log::SetOutputLevel debugLevel(Logger::DEBUG2);
116 #endif
117
118         parseCommandFile();
119         assert(m_ast);
120         
121         ListASTNode * blocks = m_ast->getBlocks();
122         if (!blocks)
123         {
124                 throw std::runtime_error("command file has no blocks");
125         }
126         
127         ListASTNode::iterator it = blocks->begin();
128         for (; it != blocks->end(); ++it)
129         {
130                 ASTNode * node = *it;
131                 
132                 // Handle an options block.
133                 OptionsBlockASTNode * options = dynamic_cast<OptionsBlockASTNode *>(node);
134                 if (options)
135                 {
136                         processOptions(options->getOptions());
137                         continue;
138                 }
139                 
140                 // Handle a constants block.
141                 ConstantsBlockASTNode * constants = dynamic_cast<ConstantsBlockASTNode *>(node);
142                 if (constants)
143                 {
144                         processConstants(constants->getConstants());
145                         continue;
146                 }
147                 
148                 // Handle a sources block.
149                 SourcesBlockASTNode * sources = dynamic_cast<SourcesBlockASTNode *>(node);
150                 if (sources)
151                 {
152                         processSources(sources->getSources());
153                 }
154         }
155         
156         processSections(m_ast->getSections());
157 }
158
159 //! Opens the command file and runs it through the lexer and parser. The resulting
160 //! abstract syntax tree is held in the m_ast member variable. After parsing, the
161 //! command file is closed.
162 //!
163 //! \exception std::runtime_error Several problems will cause this exception to be
164 //!             raised, including an unspecified command file path or an error opening the
165 //!             file.
166 void ConversionController::parseCommandFile()
167 {
168         if (!m_commandFilePath)
169         {
170                 throw std::runtime_error("no command file path was provided");
171         }
172         
173         // Search for command file
174         std::string actualPath;
175         bool found = PathSearcher::getGlobalSearcher().search(*m_commandFilePath, PathSearcher::kFindFile, true, actualPath);
176         if (!found)
177         {
178                 throw runtime_error(format_string("unable to find command file %s\n", m_commandFilePath->c_str()));
179         }
180
181         // open command file
182         std::ifstream commandFile(actualPath.c_str(), ios_base::in | ios_base::binary);
183         if (!commandFile.is_open())
184         {
185                 throw std::runtime_error("could not open command file");
186         }
187         
188         try
189         {
190                 // create lexer instance
191                 ElftosbLexer lexer(commandFile);
192 //              testLexer(lexer);
193                 
194                 CommandFileASTNode * ast = NULL;
195                 int result = yyparse(&lexer, &ast);
196                 m_ast = ast;
197                 
198                 // check results
199                 if (result || !m_ast)
200                 {
201                         throw std::runtime_error("failed to parse command file");
202                 }
203                 
204                 // dump AST
205 //              m_ast->printTree(0);
206                 
207                 // close command file
208                 commandFile.close();
209         }
210         catch (...)
211         {
212                 // close command file
213                 commandFile.close();
214                 
215                 // rethrow exception
216                 throw;
217         }
218 }
219
220 //! Iterates over the option definition AST nodes. elftosb::Value objects are created for
221 //! each option value and added to the option dictionary.
222 //!
223 //! \exception std::runtime_error Various errors will cause this exception to be thrown. These
224 //!             include AST nodes being an unexpected type or expression not evaluating to integers.
225 void ConversionController::processOptions(ListASTNode * options)
226 {
227         if (!options)
228         {
229                 return;
230         }
231         
232         ListASTNode::iterator it = options->begin();
233         for (; it != options->end(); ++it)
234         {
235                 std::string ident;
236                 Value * value = convertAssignmentNodeToValue(*it, ident);
237                 
238                 // check if this option has already been set
239                 if (hasOption(ident))
240                 {
241                         throw semantic_error(format_string("line %d: option already set", (*it)->getFirstLine()));
242                 }
243                 
244                 // now save the option value in our map
245                 if (value)
246                 {
247                         setOption(ident, value);
248                 }
249         }
250 }
251
252 //! Scans the constant definition AST nodes, evaluates expression nodes by calling their
253 //! elftosb::ExprASTNode::reduce() method, and updates the evaluation context member so
254 //! those constant values can be used in other expressions.
255 //!
256 //! \exception std::runtime_error Various errors will cause this exception to be thrown. These
257 //!             include AST nodes being an unexpected type or expression not evaluating to integers.
258 void ConversionController::processConstants(ListASTNode * constants)
259 {
260         if (!constants)
261         {
262                 return;
263         }
264         
265         ListASTNode::iterator it = constants->begin();
266         for (; it != constants->end(); ++it)
267         {
268                 std::string ident;
269                 Value * value = convertAssignmentNodeToValue(*it, ident);
270                 
271                 SizedIntegerValue * intValue = dynamic_cast<SizedIntegerValue*>(value);
272                 if (!intValue)
273                 {
274                         throw semantic_error(format_string("line %d: constant value is an invalid type", (*it)->getFirstLine()));
275                 }
276                                 
277 //#if PRINT_VALUES
278 //              Log::log("constant ");
279 //              printIntConstExpr(ident, intValue);
280 //#endif
281                 
282                 // record this constant's value in the evaluation context
283                 m_context.setVariable(ident, intValue->getValue(), intValue->getWordSize());
284         }
285 }
286
287 //! \exception std::runtime_error Various errors will cause this exception to be thrown. These
288 //!             include AST nodes being an unexpected type or expression not evaluating to integers.
289 //!
290 //! \todo Handle freeing of dict if an exception occurs.
291 void ConversionController::processSources(ListASTNode * sources)
292 {
293         if (!sources)
294         {
295                 return;
296         }
297         
298         ListASTNode::iterator it = sources->begin();
299         for (; it != sources->end(); ++it)
300         {
301                 SourceDefASTNode * node = dynamic_cast<SourceDefASTNode*>(*it);
302                 if (!node)
303                 {
304                         throw semantic_error(format_string("line %d: source definition node is an unexpected type", node->getFirstLine()));
305                 }
306                 
307                 // get source name and check if it has already been defined
308                 std::string * name = node->getName();
309                 if (m_sources.find(*name) != m_sources.end())
310                 {
311                         // can't define a source multiple times
312                         throw semantic_error(format_string("line %d: source already defined", node->getFirstLine()));
313                 }
314                 
315                 // convert attributes into an option dict
316                 OptionDictionary * dict = new OptionDictionary(this);
317                 ListASTNode * attrsNode = node->getAttributes();
318                 if (attrsNode)
319                 {
320                         ListASTNode::iterator attrIt = attrsNode->begin();
321                         for (; attrIt != attrsNode->end(); ++attrIt)
322                         {
323                                 std::string ident;
324                                 Value * value = convertAssignmentNodeToValue(*attrIt, ident);
325                                 dict->setOption(ident, value);
326                         }
327                 }
328                 
329                 // figure out which type of source definition this is
330                 PathSourceDefASTNode * pathNode = dynamic_cast<PathSourceDefASTNode*>(node);
331                 ExternSourceDefASTNode * externNode = dynamic_cast<ExternSourceDefASTNode*>(node);
332                 SourceFile * file = NULL;
333                 
334                 if (pathNode)
335                 {
336                         // explicit path
337                         std::string * path = pathNode->getPath();
338                         
339 #if PRINT_VALUES
340                         Log::log("source %s => path(%s)\n", name->c_str(), path->c_str());
341 #endif
342                         
343                         try
344                         {
345                                 file = SourceFile::openFile(*path);
346                         }
347                         catch (...)
348                         {
349                                 // file doesn't exist
350                                 Log::log(Logger::INFO2, "failed to open source file: %s (ignoring for now)\n", path->c_str());
351                                 m_failedSources.push_back(*name);
352                         }
353                 }
354                 else if (externNode)
355                 {
356                         // externally provided path
357                         ExprASTNode * expr = externNode->getSourceNumberExpr()->reduce(m_context);
358                         IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(expr);
359                         if (!intConst)
360                         {
361                                 throw semantic_error(format_string("line %d: expression didn't evaluate to an integer", expr->getFirstLine()));
362                         }
363                         
364                         uint32_t externalFileNumber = static_cast<uint32_t>(intConst->getValue());
365                         
366                         // make sure the extern number is valid
367                         if (externalFileNumber >= 0 && externalFileNumber < m_externPaths.size())
368                         {
369                         
370 #if PRINT_VALUES
371                         Log::log("source %s => extern(%d=%s)\n", name->c_str(), externalFileNumber, m_externPaths[externalFileNumber].c_str());
372 #endif
373                         
374                                 try
375                                 {
376                                         file = SourceFile::openFile(m_externPaths[externalFileNumber]);
377                                 }
378                                 catch (...)
379                                 {
380                                         Log::log(Logger::INFO2, "failed to open source file: %s (ignoring for now)\n", m_externPaths[externalFileNumber].c_str());
381                                         m_failedSources.push_back(*name);
382                                 }
383                         }
384                 }
385                 else
386                 {
387                         throw semantic_error(format_string("line %d: unexpected source definition node type", node->getFirstLine()));
388                 }
389                 
390                 if (file)
391                 {
392                         // set options
393                         file->setOptions(dict);
394                         
395                         // stick the file object in the source map
396                         m_sources[*name] = file;
397                 }
398         }
399 }
400
401 void ConversionController::processSections(ListASTNode * sections)
402 {
403         if (!sections)
404         {
405                 Log::log(Logger::WARNING, "warning: no sections were defined in command file");
406                 return;
407         }
408         
409         ListASTNode::iterator it = sections->begin();
410         for (; it != sections->end(); ++it)
411         {
412                 SectionContentsASTNode * node = dynamic_cast<SectionContentsASTNode*>(*it);
413                 if (!node)
414                 {
415                         throw semantic_error(format_string("line %d: section definition is unexpected type", node->getFirstLine()));
416                 }
417                 
418                 // evaluate section number
419                 ExprASTNode * idExpr = node->getSectionNumberExpr()->reduce(m_context);
420                 IntConstExprASTNode * idConst = dynamic_cast<IntConstExprASTNode*>(idExpr);
421                 if (!idConst)
422                 {
423                         throw semantic_error(format_string("line %d: section number did not evaluate to an integer", idExpr->getFirstLine()));
424                 }
425                 uint32_t sectionID = idConst->getValue();
426                 
427                 // Create options context for this section. The options context has the
428                 // conversion controller as its parent context so it will inherit global options.
429                 // The context will be set in the section after the section is created below.
430                 OptionDictionary * optionsDict = new OptionDictionary(this);
431                 ListASTNode * attrsNode = node->getOptions();
432                 if (attrsNode)
433                 {
434                         ListASTNode::iterator attrIt = attrsNode->begin();
435                         for (; attrIt != attrsNode->end(); ++attrIt)
436                         {
437                                 std::string ident;
438                                 Value * value = convertAssignmentNodeToValue(*attrIt, ident);
439                                 optionsDict->setOption(ident, value);
440                         }
441                 }
442                 
443                 // Now create the actual section object based on its type.
444                 OutputSection * outputSection = NULL;
445                 BootableSectionContentsASTNode * bootableSection;
446                 DataSectionContentsASTNode * dataSection;
447                 if (bootableSection = dynamic_cast<BootableSectionContentsASTNode*>(node))
448                 {               
449                         // process statements into a sequence of operations
450                         ListASTNode * statements = bootableSection->getStatements();
451                         OperationSequence * sequence = convertStatementList(statements);
452
453 #if 0
454                         Log::log("section ID = %d\n", sectionID);
455                         statements->printTree(0);
456                         
457                         Log::log("sequence has %d operations\n", sequence->getCount());
458                         OperationSequence::iterator_t it = sequence->begin();
459                         for (; it != sequence->end(); ++it)
460                         {
461                                 Operation * op = *it;
462                                 Log::log("op = %p\n", op);
463                         }
464 #endif
465                         
466                         // create the output section and add it to the list
467                         OperationSequenceSection * opSection = new OperationSequenceSection(sectionID);
468                         opSection->setOptions(optionsDict);
469                         opSection->getSequence() += sequence;
470                         outputSection = opSection;
471                 }
472                 else if (dataSection = dynamic_cast<DataSectionContentsASTNode*>(node))
473                 {
474                         outputSection = convertDataSection(dataSection, sectionID, optionsDict);
475                 }
476                 else
477                 {
478                         throw semantic_error(format_string("line %d: unexpected section contents type", node->getFirstLine()));
479                 }
480                 
481                 if (outputSection)
482                 {
483                         m_outputSections.push_back(outputSection);
484                 }
485         }
486 }
487
488 //! Creates an instance of BinaryDataSection from the AST node passed in the
489 //! \a dataSection parameter. The section-specific options for this node will
490 //! have already been converted into an OptionDictionary, the one passed in
491 //! the \a optionsDict parameter.
492 //!
493 //! The \a dataSection node will have as its contents one of the AST node
494 //! classes that represents a source of data. The member function
495 //! createSourceFromNode() is used to convert this AST node into an
496 //! instance of a DataSource subclass. Then the method imageDataSource()
497 //! converts the segments of the DataSource into a raw binary buffer that
498 //! becomes the contents of the BinaryDataSection this is returned.
499 //!
500 //! \param dataSection The AST node for the data section.
501 //! \param sectionID Unique tag value the user has assigned to this section.
502 //! \param optionsDict Options that apply only to this section. This dictionary
503 //!             will be assigned as the options dictionary for the resulting section
504 //!             object. Its parent is the conversion controller itself.
505 //! \return An instance of BinaryDataSection. Its contents are a contiguous
506 //!             binary representation of the contents of \a dataSection.
507 OutputSection * ConversionController::convertDataSection(DataSectionContentsASTNode * dataSection, uint32_t sectionID, OptionDictionary * optionsDict)
508 {
509         // Create a data source from the section contents AST node.
510         ASTNode * contents = dataSection->getContents();
511         DataSource * dataSource = createSourceFromNode(contents);
512         
513         // Convert the data source to a raw buffer.
514         DataSourceImager imager;
515         imager.addDataSource(dataSource);
516         
517         // Then make a data section from the buffer.
518         BinaryDataSection * resultSection = new BinaryDataSection(sectionID);
519         resultSection->setOptions(optionsDict);
520         if (imager.getLength())
521         {
522                 resultSection->setData(imager.getData(), imager.getLength());
523         }
524         
525         return resultSection;
526 }
527
528 //! @param node The AST node instance for the assignment expression.
529 //! @param[out] ident Upon exit this string will be set the the left hand side of the
530 //!             assignment expression, the identifier name.
531 //!
532 //! @return An object that is a subclass of Value is returned. The specific subclass will
533 //!             depend on the type of the right hand side of the assignment expression whose AST
534 //!             node was provided in the @a node argument.
535 //!
536 //! @exception semantic_error Thrown for any error where an AST node is an unexpected type.
537 //!             This may be the @a node argument itself, if it is not an AssignmentASTNode. Or it
538 //!             may be an unexpected type for either the right or left hand side of the assignment.
539 //!             The message for the exception will contain a description of the error.
540 Value * ConversionController::convertAssignmentNodeToValue(ASTNode * node, std::string & ident)
541 {
542         Value * resultValue = NULL;
543         
544         // each item of the options list should be an assignment node
545         AssignmentASTNode * assignmentNode = dynamic_cast<AssignmentASTNode*>(node);
546         if (!node)
547         {
548                 throw semantic_error(format_string("line %d: node is wrong type", assignmentNode->getFirstLine()));
549         }
550         
551         // save the left hand side (the identifier) into ident
552         ident = *assignmentNode->getIdent();
553         
554         // get the right hand side and convert it to a Value instance
555         ASTNode * valueNode = assignmentNode->getValue();
556         StringConstASTNode * str;
557         ExprASTNode * expr;
558         if (str = dynamic_cast<StringConstASTNode*>(valueNode))
559         {
560                 // the option value is a string constant
561                 resultValue = new StringValue(str->getString());
562
563 //#if PRINT_VALUES
564 //              Log::log("option %s => \'%s\'\n", ident->c_str(), str->getString()->c_str());
565 //#endif
566         }
567         else if (expr = dynamic_cast<ExprASTNode*>(valueNode))
568         {
569                 ExprASTNode * reducedExpr = expr->reduce(m_context);
570                 IntConstExprASTNode * intConst = dynamic_cast<IntConstExprASTNode*>(reducedExpr);
571                 if (!intConst)
572                 {
573                         throw semantic_error(format_string("line %d: expression didn't evaluate to an integer", expr->getFirstLine()));
574                 }
575                 
576 //#if PRINT_VALUES
577 //              Log::log("option ");
578 //              printIntConstExpr(*ident, intConst);
579 //#endif
580                 
581                 resultValue = new SizedIntegerValue(intConst->getValue(), intConst->getSize());
582         }
583         else
584         {
585                 throw semantic_error(format_string("line %d: right hand side node is an unexpected type", valueNode->getFirstLine()));
586         }
587         
588         return resultValue;
589 }
590
591 //! Builds up a sequence of Operation objects that are equivalent to the
592 //! statements in the \a statements list. The statement list is simply iterated
593 //! over and the results of convertOneStatement() are used to build up
594 //! the final result sequence.
595 //!
596 //! \see convertOneStatement()
597 OperationSequence * ConversionController::convertStatementList(ListASTNode * statements)
598 {
599         OperationSequence * resultSequence = new OperationSequence();
600         ListASTNode::iterator it = statements->begin();
601         for (; it != statements->end(); ++it)
602         {
603                 StatementASTNode * statement = dynamic_cast<StatementASTNode*>(*it);
604                 if (!statement)
605                 {
606                         throw semantic_error(format_string("line %d: statement node is unexpected type", (*it)->getFirstLine()));
607                 }
608                 
609                 // convert this statement and append it to the result
610                 OperationSequence * sequence = convertOneStatement(statement);
611                 if (sequence)
612                 {
613                         *resultSequence += sequence;
614                 }
615         }
616         
617         return resultSequence;
618 }
619
620 //! Uses C++ RTTI to identify the particular subclass of StatementASTNode that
621 //! the \a statement argument matches. Then the appropriate conversion method
622 //! is called.
623 //!
624 //! \see convertLoadStatement()
625 //! \see convertCallStatement()
626 //! \see convertFromStatement()
627 OperationSequence * ConversionController::convertOneStatement(StatementASTNode * statement)
628 {
629         // see if it's a load statement
630         LoadStatementASTNode * load = dynamic_cast<LoadStatementASTNode*>(statement);
631         if (load)
632         {
633                 return convertLoadStatement(load);
634         }
635         
636         // see if it's a call statement
637         CallStatementASTNode * call = dynamic_cast<CallStatementASTNode*>(statement);
638         if (call)
639         {
640                 return convertCallStatement(call);
641         }
642         
643         // see if it's a from statement
644         FromStatementASTNode * from = dynamic_cast<FromStatementASTNode*>(statement);
645         if (from)
646         {
647                 return convertFromStatement(from);
648         }
649         
650         // see if it's a mode statement
651         ModeStatementASTNode * mode = dynamic_cast<ModeStatementASTNode*>(statement);
652         if (mode)
653         {
654                 return convertModeStatement(mode);
655         }
656         
657         // see if it's an if statement
658         IfStatementASTNode * ifStmt = dynamic_cast<IfStatementASTNode*>(statement);
659         if (ifStmt)
660         {
661                 return convertIfStatement(ifStmt);
662         }
663         
664         // see if it's a message statement
665         MessageStatementASTNode * messageStmt = dynamic_cast<MessageStatementASTNode*>(statement);
666         if (messageStmt)
667         {
668                 // Message statements don't produce operation sequences.
669                 handleMessageStatement(messageStmt);
670                 return NULL;
671         }
672         
673         // didn't match any of the expected statement types
674         throw semantic_error(format_string("line %d: unexpected statement type", statement->getFirstLine()));
675         return NULL;
676 }
677
678 //! Possible load data node types:
679 //! - StringConstASTNode
680 //! - ExprASTNode
681 //! - SourceASTNode
682 //! - SectionMatchListASTNode
683 //!
684 //! Possible load target node types:
685 //! - SymbolASTNode
686 //! - NaturalLocationASTNode
687 //! - AddressRangeASTNode
688 OperationSequence * ConversionController::convertLoadStatement(LoadStatementASTNode * statement)
689 {
690         LoadOperation * op = NULL;
691         
692         try
693         {
694                 // build load operation from source and target
695                 op = new LoadOperation();
696                 op->setSource(createSourceFromNode(statement->getData()));
697                 op->setTarget(createTargetFromNode(statement->getTarget()));
698                 op->setDCDLoad(statement->isDCDLoad());
699                 
700                 return new OperationSequence(op);
701         }
702         catch (...)
703         {
704                 if (op)
705                 {
706                         delete op;
707                 }
708                 throw;
709         }
710 }
711
712 //! Possible call target node types:
713 //! - SymbolASTNode
714 //! - ExprASTNode
715 //!
716 //! Possible call argument node types:
717 //! - ExprASTNode
718 //! - NULL
719 OperationSequence * ConversionController::convertCallStatement(CallStatementASTNode * statement)
720 {
721         ExecuteOperation * op = NULL;
722         
723         try
724         {
725                 // create operation from AST nodes
726                 op = new ExecuteOperation();
727                 
728                 bool isHAB = statement->isHAB();
729                 
730                 op->setTarget(createTargetFromNode(statement->getTarget()));
731                 
732                 // set argument value, which defaults to 0 if no expression was provided
733                 uint32_t arg = 0;
734                 ASTNode * argNode = statement->getArgument();
735                 if (argNode)
736                 {
737                         ExprASTNode * argExprNode = dynamic_cast<ExprASTNode*>(argNode);
738                         if (!argExprNode)
739                         {
740                                 throw semantic_error(format_string("line %d: call argument is unexpected type", argNode->getFirstLine()));
741                         }
742                         argExprNode = argExprNode->reduce(m_context);
743                         IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(argExprNode);
744                         if (!intNode)
745                         {
746                                 throw semantic_error(format_string("line %d: call argument did not evaluate to an integer", argExprNode->getFirstLine()));
747                         }
748                         
749                         arg = intNode->getValue();
750                 }
751                 op->setArgument(arg);
752                 
753                 // set call type
754                 switch (statement->getCallType())
755                 {
756                         case CallStatementASTNode::kCallType:
757                                 op->setExecuteType(ExecuteOperation::kCall);
758                                 break;
759                         case CallStatementASTNode::kJumpType:
760                                 op->setExecuteType(ExecuteOperation::kJump);
761                                 break;
762                 }
763                 
764                 // Set the HAB mode flag.
765                 op->setIsHAB(isHAB);
766                 
767                 return new OperationSequence(op);
768         }
769         catch (...)
770         {
771                 // delete op and rethrow exception
772                 if (op)
773                 {
774                         delete op;
775                 }
776                 throw;
777         }
778 }
779
780 //! First this method sets the default source to the source identified in
781 //! the from statement. Then the statements within the from block are
782 //! processed recursively by calling convertStatementList(). The resulting
783 //! operation sequence is returned.
784 OperationSequence * ConversionController::convertFromStatement(FromStatementASTNode * statement)
785 {
786         if (m_defaultSource)
787         {
788                 throw semantic_error(format_string("line %d: from statements cannot be nested", statement->getFirstLine()));
789         }
790         
791         // look up source file instance
792         std::string * fromSourceName = statement->getSourceName();
793         assert(fromSourceName);
794         
795         // make sure it's a valid source name
796         source_map_t::iterator sourceIt = m_sources.find(*fromSourceName);
797         if (sourceIt == m_sources.end())
798         {
799                 throw semantic_error(format_string("line %d: bad source name", statement->getFirstLine()));
800         }
801         
802         // set default source
803         m_defaultSource = sourceIt->second;
804         assert(m_defaultSource);
805         
806         // get statements inside the from block
807         ListASTNode * fromStatements = statement->getStatements();
808         assert(fromStatements);
809         
810         // produce resulting operation sequence
811         OperationSequence * result = convertStatementList(fromStatements);
812         
813         // restore default source to NULL
814         m_defaultSource = NULL;
815         
816         return result;
817 }
818
819 //! Evaluates the expression to get the new boot mode value. Then creates a
820 //! BootModeOperation object and returns an OperationSequence containing it.
821 //!
822 //! \exception elftosb::semantic_error Thrown if a semantic problem is found with
823 //!             the boot mode expression.
824 OperationSequence * ConversionController::convertModeStatement(ModeStatementASTNode * statement)
825 {
826         BootModeOperation * op = NULL;
827         
828         try
829         {
830                 op = new BootModeOperation();
831                 
832                 // evaluate the boot mode expression
833                 ExprASTNode * modeExprNode = statement->getModeExpr();
834                 if (!modeExprNode)
835                 {
836                         throw semantic_error(format_string("line %d: mode statement has invalid boot mode expression", statement->getFirstLine()));
837                 }
838                 modeExprNode = modeExprNode->reduce(m_context);
839                 IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(modeExprNode);
840                 if (!intNode)
841                 {
842                         throw semantic_error(format_string("line %d: boot mode did not evaluate to an integer", statement->getFirstLine()));
843                 }
844                 
845                 op->setBootMode(intNode->getValue());
846                 
847                 return new OperationSequence(op);
848         }
849         catch (...)
850         {
851                 if (op)
852                 {
853                         delete op;
854                 }
855                 
856                 // rethrow exception
857                 throw;
858         }
859 }
860
861 //! Else branches, including else-if, are handled recursively, so there is a limit
862 //! on the number of them based on the stack size.
863 //!
864 //! \return Returns the operation sequence for the branch of the if statement that
865 //!             evaluated to true. If the statement did not have an else branch and the
866 //!             condition expression evaluated to false, then NULL will be returned.
867 //!
868 //! \todo Handle else branches without recursion.
869 OperationSequence * ConversionController::convertIfStatement(IfStatementASTNode * statement)
870 {
871         // Get the if's conditional expression.
872         ExprASTNode * conditionalExpr = statement->getConditionExpr();
873         if (!conditionalExpr)
874         {
875                 throw semantic_error(format_string("line %d: missing or invalid conditional expression", statement->getFirstLine()));
876         }
877         
878         // Reduce the conditional to a single integer.
879         conditionalExpr = conditionalExpr->reduce(m_context);
880         IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(conditionalExpr);
881         if (!intNode)
882         {
883                 throw semantic_error(format_string("line %d: if statement conditional expression did not evaluate to an integer", statement->getFirstLine()));
884         }
885         
886         // Decide which statements to further process by the conditional's boolean value.
887         if (intNode->getValue() && statement->getIfStatements())
888         {
889                 return convertStatementList(statement->getIfStatements());
890         }
891         else if (statement->getElseStatements())
892         {
893                 return convertStatementList(statement->getElseStatements());
894         }
895         else
896         {
897                 // No else branch and the conditional was false, so there are no operations to return.
898                 return NULL;
899         }
900 }
901
902 //! Message statements are executed immediately, by this method. They are
903 //! not converted into an abstract operation. All messages are passed through
904 //! substituteVariables() before being output.
905 //!
906 //! \param statement The message statement AST node object.
907 void ConversionController::handleMessageStatement(MessageStatementASTNode * statement)
908 {
909         string * message = statement->getMessage();
910         if (!message)
911         {
912                 throw runtime_error("message statement had no message");
913         }
914         
915         smart_ptr<string> finalMessage = substituteVariables(message);
916         
917         switch (statement->getType())
918         {
919                 case MessageStatementASTNode::kInfo:
920                         Log::log(Logger::INFO, "%s\n", finalMessage->c_str());
921                         break;
922                 
923                 case MessageStatementASTNode::kWarning:
924                         Log::log(Logger::WARNING, "warning: %s\n", finalMessage->c_str());
925                         break;
926                 
927                 case MessageStatementASTNode::kError:
928                         throw runtime_error(*finalMessage);
929                         break;
930         }
931 }
932
933 //! Performs shell-like variable substitution on the string passed into it.
934 //! Both sources and constants can be substituted. Sources will be replaced
935 //! with their path and constants with their integer value. The syntax allows
936 //! for some simple formatting for constants.
937 //!
938 //! The syntax is mostly standard. A substitution begins with a dollar-sign
939 //! and is followed by the source or constant name in parentheses. For instance,
940 //! "$(mysource)" or "$(myconst)". The parentheses are always required.
941 //!
942 //! Constant names can be prefixed by a single formatting character followed
943 //! by a colon. The only formatting characters currently supported are 'd' for
944 //! decimal and 'x' for hex. For example, "$(x:myconst)" will be replaced with
945 //! the value of the constant named "myconst" formatted as hexadecimal. The
946 //! default is decimal, so the 'd' formatting character isn't really ever
947 //! needed.
948 //!
949 //! \param message The string to perform substitution on.
950 //! \return Returns a newly allocated std::string object that has all
951 //!             substitutions replaced with the associated value. The caller is
952 //!             responsible for freeing the string object using the delete operator.
953 std::string * ConversionController::substituteVariables(const std::string * message)
954 {
955         string * result = new string();
956         int i;
957         int state = 0;
958         string name;
959         
960         for (i=0; i < message->size(); ++i)
961         {
962                 char c = (*message)[i];
963                 switch (state)
964                 {
965                         case 0:
966                                 if (c == '$')
967                                 {
968                                         state = 1;
969                                 }
970                                 else
971                                 {
972                                         (*result) += c;
973                                 }
974                                 break;
975                         
976                         case 1:
977                                 if (c == '(')
978                                 {
979                                         state = 2;
980                                 }
981                                 else
982                                 {
983                                         // Wasn't a variable substitution, so revert to initial state after
984                                         // inserting the original characters.
985                                         (*result) += '$';
986                                         (*result) += c;
987                                         state = 0;
988                                 }
989                                 break;
990                         
991                         case 2:
992                                 if (c == ')')
993                                 {
994                                         // Try the name as a source name first.
995                                         if (m_sources.find(name) != m_sources.end())
996                                         {
997                                                 (*result) += m_sources[name]->getPath();
998                                         }
999                                         // Otherwise try it as a variable.
1000                                         else
1001                                         {
1002                                                 // Select format.
1003                                                 const char * fmt = "%d";
1004                                                 if (name[1] == ':' && (name[0] == 'd' || name[0] == 'x'))
1005                                                 {
1006                                                         if (name[0] == 'x')
1007                                                         {
1008                                                                 fmt = "0x%x";
1009                                                         }
1010                                                         
1011                                                         // Delete the format characters.
1012                                                         name.erase(0, 2);
1013                                                 }
1014                                                 
1015                                                 // Now insert the formatted variable if it exists.
1016                                                 if (m_context.isVariableDefined(name))
1017                                                 {
1018                                                         (*result) += format_string(fmt, m_context.getVariableValue(name));
1019                                                 }
1020                                         }
1021                                         
1022                                         // Switch back to initial state and clear name.
1023                                         state = 0;
1024                                         name.clear();
1025                                 }
1026                                 else
1027                                 {
1028                                         // Just keep building up the variable name.
1029                                         name += c;
1030                                 }
1031                                 break;
1032                 }
1033         }
1034         
1035         return result;
1036 }
1037
1038 //!
1039 //! \param generator The generator to use.
1040 BootImage * ConversionController::generateOutput(BootImageGenerator * generator)
1041 {
1042         // set the generator's option context
1043         generator->setOptionContext(this);
1044         
1045         // add output sections to the generator in sequence
1046         section_vector_t::iterator it = m_outputSections.begin();
1047         for (; it != m_outputSections.end(); ++it)
1048         {
1049                 generator->addOutputSection(*it);
1050         }
1051         
1052         // and produce the output
1053         BootImage * image = generator->generate();
1054 //      Log::log("boot image = %p\n", image);
1055         return image;
1056 }
1057
1058 //! Takes an AST node that is one of the following subclasses and creates the corresponding
1059 //! type of DataSource object from it.
1060 //! - StringConstASTNode
1061 //! - ExprASTNode
1062 //! - SourceASTNode
1063 //! - SectionASTNode
1064 //! - SectionMatchListASTNode
1065 //! - BlobConstASTNode
1066 //! - IVTConstASTNode
1067 //!
1068 //! \exception elftosb::semantic_error Thrown if a semantic problem is found with
1069 //!             the data node.
1070 //! \exception std::runtime_error Thrown if an error occurs that shouldn't be possible
1071 //!             based on the grammar.
1072 DataSource * ConversionController::createSourceFromNode(ASTNode * dataNode)
1073 {
1074         assert(dataNode);
1075         
1076         DataSource * source = NULL;
1077         StringConstASTNode * stringNode;
1078         BlobConstASTNode * blobNode;
1079         ExprASTNode * exprNode;
1080         SourceASTNode * sourceNode;
1081         SectionASTNode * sectionNode;
1082         SectionMatchListASTNode * matchListNode;
1083     IVTConstASTNode * ivtNode;
1084         
1085         if (stringNode = dynamic_cast<StringConstASTNode*>(dataNode))
1086         {
1087                 // create a data source with the string contents
1088                 std::string * stringData = stringNode->getString();
1089                 const uint8_t * stringContents = reinterpret_cast<const uint8_t *>(stringData->c_str());
1090                 source = new UnmappedDataSource(stringContents, static_cast<unsigned>(stringData->size()));
1091         }
1092         else if (blobNode = dynamic_cast<BlobConstASTNode*>(dataNode))
1093         {
1094                 // create a data source with the raw binary data
1095                 Blob * blob = blobNode->getBlob();
1096                 source = new UnmappedDataSource(blob->getData(), blob->getLength());
1097         }
1098         else if (exprNode = dynamic_cast<ExprASTNode*>(dataNode))
1099         {
1100                 // reduce the expression first
1101                 exprNode = exprNode->reduce(m_context);
1102                 IntConstExprASTNode * intNode = dynamic_cast<IntConstExprASTNode*>(exprNode);
1103                 if (!intNode)
1104                 {
1105                         throw semantic_error("load pattern expression did not evaluate to an integer");
1106                 }
1107                 
1108                 SizedIntegerValue intValue(intNode->getValue(), intNode->getSize());
1109                 source = new PatternSource(intValue);
1110         }
1111         else if (sourceNode = dynamic_cast<SourceASTNode*>(dataNode))
1112         {
1113                 // load the entire source contents
1114                 SourceFile * sourceFile = getSourceFromName(sourceNode->getSourceName(), sourceNode->getFirstLine());
1115                 source = sourceFile->createDataSource();
1116         }
1117         else if (sectionNode = dynamic_cast<SectionASTNode*>(dataNode))
1118         {
1119                 // load some subset of the source
1120                 SourceFile * sourceFile = getSourceFromName(sectionNode->getSourceName(), sectionNode->getFirstLine());
1121                 if (!sourceFile->supportsNamedSections())
1122                 {
1123                         throw semantic_error(format_string("line %d: source does not support sections", sectionNode->getFirstLine()));
1124                 }
1125                 
1126                 // create data source from the section name
1127                 std::string * sectionName = sectionNode->getSectionName();
1128                 GlobMatcher globber(*sectionName);
1129                 source = sourceFile->createDataSource(globber);
1130                 if (!source)
1131                 {
1132                         throw semantic_error(format_string("line %d: no sections match the pattern", sectionNode->getFirstLine()));
1133                 }
1134         }
1135         else if (matchListNode = dynamic_cast<SectionMatchListASTNode*>(dataNode))
1136         {
1137                 SourceFile * sourceFile = getSourceFromName(matchListNode->getSourceName(), matchListNode->getFirstLine());
1138                 if (!sourceFile->supportsNamedSections())
1139                 {
1140                         throw semantic_error(format_string("line %d: source type does not support sections", matchListNode->getFirstLine()));
1141                 }
1142                 
1143                 // create string matcher
1144                 ExcludesListMatcher matcher;
1145                 
1146                 // add each pattern to the matcher
1147                 ListASTNode * matchList = matchListNode->getSections();
1148                 ListASTNode::iterator it = matchList->begin();
1149                 for (; it != matchList->end(); ++it)
1150                 {
1151                         ASTNode * node = *it;
1152                         sectionNode = dynamic_cast<SectionASTNode*>(node);
1153                         if (!sectionNode)
1154                         {
1155                                 throw std::runtime_error(format_string("line %d: unexpected node type in section pattern list", (*it)->getFirstLine()));
1156                         }
1157                         bool isInclude = sectionNode->getAction() == SectionASTNode::kInclude;
1158                         matcher.addPattern(isInclude, *(sectionNode->getSectionName()));
1159                 }
1160                 
1161                 // create data source from the section match list
1162                 source = sourceFile->createDataSource(matcher);
1163                 if (!source)
1164                 {
1165                         throw semantic_error(format_string("line %d: no sections match the section pattern list", matchListNode->getFirstLine()));
1166                 }
1167         }
1168     else if (ivtNode = dynamic_cast<IVTConstASTNode*>(dataNode))
1169     {
1170         source = createIVTDataSource(ivtNode);
1171     }
1172         else
1173         {
1174                 throw semantic_error(format_string("line %d: unexpected load data node type", dataNode->getFirstLine()));
1175         }
1176         
1177         return source;
1178 }
1179
1180 DataSource * ConversionController::createIVTDataSource(IVTConstASTNode * ivtNode)
1181 {
1182     IVTDataSource * source = new IVTDataSource;
1183     
1184     // Iterate over the assignment statements in the IVT definition.
1185     ListASTNode * fieldList = ivtNode->getFieldAssignments();
1186     
1187     if (fieldList)
1188     {
1189         ListASTNode::iterator it = fieldList->begin();
1190         for (; it != fieldList->end(); ++it)
1191         {
1192             AssignmentASTNode * assignmentNode = dynamic_cast<AssignmentASTNode*>(*it);
1193             if (!assignmentNode)
1194             {
1195                 throw std::runtime_error(format_string("line %d: unexpected node type in IVT definition", (*it)->getFirstLine()));
1196             }
1197             
1198             // Get the IVT field name.
1199             std::string * fieldName = assignmentNode->getIdent();
1200             
1201             // Reduce the field expression and get the integer result.
1202             ASTNode * valueNode = assignmentNode->getValue();
1203             ExprASTNode * valueExpr = dynamic_cast<ExprASTNode*>(valueNode);
1204             if (!valueExpr)
1205             {
1206                 throw semantic_error("IVT field must have a valid expression");
1207             }
1208             IntConstExprASTNode * valueIntExpr = dynamic_cast<IntConstExprASTNode*>(valueExpr->reduce(m_context));
1209             if (!valueIntExpr)
1210             {
1211                 throw semantic_error(format_string("line %d: IVT field '%s' does not evaluate to an integer", valueNode->getFirstLine(), fieldName->c_str()));
1212             }
1213             uint32_t value = static_cast<uint32_t>(valueIntExpr->getValue());
1214             
1215             // Set the field in the IVT data source.
1216             if (!source->setFieldByName(*fieldName, value))
1217             {
1218                 throw semantic_error(format_string("line %d: unknown IVT field '%s'", assignmentNode->getFirstLine(), fieldName->c_str()));
1219             }
1220         }
1221     }
1222     
1223     return source;
1224 }
1225
1226 //! Takes an AST node subclass and returns an appropriate DataTarget object that contains
1227 //! the same information. Supported AST node types are:
1228 //! - SymbolASTNode
1229 //! - NaturalLocationASTNode
1230 //! - AddressRangeASTNode
1231 //!
1232 //! \exception elftosb::semantic_error Thrown if a semantic problem is found with
1233 //!             the target node.
1234 DataTarget * ConversionController::createTargetFromNode(ASTNode * targetNode)
1235 {
1236         assert(targetNode);
1237         
1238         DataTarget * target = NULL;
1239         SymbolASTNode * symbolNode;
1240         NaturalLocationASTNode * naturalNode;
1241         AddressRangeASTNode * addressNode;
1242         
1243         if (symbolNode = dynamic_cast<SymbolASTNode*>(targetNode))
1244         {
1245                 SourceFile * sourceFile = getSourceFromName(symbolNode->getSource(), symbolNode->getFirstLine());
1246                 std::string * symbolName = symbolNode->getSymbolName();
1247                 
1248                 // symbol name is optional
1249                 if (symbolName)
1250                 {
1251                         if (!sourceFile->supportsNamedSymbols())
1252                         {
1253                                 throw std::runtime_error(format_string("line %d: source does not support symbols", symbolNode->getFirstLine()));
1254                         }
1255                         
1256                         target = sourceFile->createDataTargetForSymbol(*symbolName);
1257                         if (!target)
1258                         {
1259                                 throw std::runtime_error(format_string("line %d: source does not have a symbol with that name", symbolNode->getFirstLine()));
1260                         }
1261                 }
1262                 else
1263                 {
1264                         // no symbol name was specified so use entry point
1265                         target = sourceFile->createDataTargetForEntryPoint();
1266                         if (!target)
1267                         {
1268                                 throw std::runtime_error(format_string("line %d: source does not have an entry point", symbolNode->getFirstLine()));
1269                         }
1270                 }
1271         }
1272         else if (naturalNode = dynamic_cast<NaturalLocationASTNode*>(targetNode))
1273         {
1274                 // the target is the source's natural location
1275                 target = new NaturalDataTarget();
1276         }
1277         else if (addressNode = dynamic_cast<AddressRangeASTNode*>(targetNode))
1278         {
1279                 // evaluate begin address
1280                 ExprASTNode * beginExpr = dynamic_cast<ExprASTNode*>(addressNode->getBegin());
1281                 if (!beginExpr)
1282                 {
1283                         throw semantic_error("address range must always have a beginning expression");
1284                 }
1285                 IntConstExprASTNode * beginIntExpr = dynamic_cast<IntConstExprASTNode*>(beginExpr->reduce(m_context));
1286                 if (!beginIntExpr)
1287                 {
1288                         throw semantic_error("address range begin did not evaluate to an integer");
1289                 }
1290                 uint32_t beginAddress = static_cast<uint32_t>(beginIntExpr->getValue());
1291                 
1292                 // evaluate end address
1293                 ExprASTNode * endExpr = dynamic_cast<ExprASTNode*>(addressNode->getEnd());
1294                 uint32_t endAddress = 0;
1295                 bool hasEndAddress = false;
1296                 if (endExpr)
1297                 {
1298                         IntConstExprASTNode * endIntExpr = dynamic_cast<IntConstExprASTNode*>(endExpr->reduce(m_context));
1299                         if (!endIntExpr)
1300                         {
1301                                 throw semantic_error("address range end did not evaluate to an integer");
1302                         }
1303                         endAddress = static_cast<uint32_t>(endIntExpr->getValue());
1304                         hasEndAddress = true;
1305                 }
1306                 
1307                 // create target
1308                 if (hasEndAddress)
1309                 {
1310                         target = new ConstantDataTarget(beginAddress, endAddress);
1311                 }
1312                 else
1313                 {
1314                         target = new ConstantDataTarget(beginAddress);
1315                 }
1316         }
1317         else
1318         {
1319                 throw semantic_error("unexpected load target node type");
1320         }
1321         
1322         return target;
1323 }
1324
1325 //! \param sourceName Pointer to string containing the name of the source to look up.
1326 //!             May be NULL, in which case the default source is used.
1327 //! \param line The line number on which the source name was located.
1328 //!
1329 //! \result A source file object that was previously created in the processSources()
1330 //!             stage.
1331 //!
1332 //! \exception std::runtime_error Thrown if the source name is invalid, or if it
1333 //!             was NULL and there is no default source (i.e., we're not inside a from
1334 //!             statement).
1335 SourceFile * ConversionController::getSourceFromName(std::string * sourceName, int line)
1336 {
1337         SourceFile * sourceFile = NULL;
1338         if (sourceName)
1339         {
1340                 // look up source in map
1341                 source_map_t::iterator it = m_sources.find(*sourceName);
1342                 if (it == m_sources.end())
1343                 {
1344                         source_name_vector_t::const_iterator findIt = std::find<source_name_vector_t::const_iterator, std::string>(m_failedSources.begin(), m_failedSources.end(), *sourceName);
1345                         if (findIt != m_failedSources.end())
1346                         {
1347                                 throw semantic_error(format_string("line %d: error opening source '%s'", line, sourceName->c_str()));
1348                         }
1349                         else
1350                         {
1351                                 throw semantic_error(format_string("line %d: invalid source name '%s'", line, sourceName->c_str()));
1352                         }
1353                 }
1354                 sourceFile = it->second;
1355         }
1356         else
1357         {
1358                 // no name provided - use default source
1359                 sourceFile = m_defaultSource;
1360                 if (!sourceFile)
1361                 {
1362                         throw semantic_error(format_string("line %d: source required but no default source is available", line));
1363                 }
1364         }
1365         
1366         // open the file if it hasn't already been
1367         if (!sourceFile->isOpen())
1368         {
1369                 sourceFile->open();
1370         }
1371         return sourceFile;
1372 }
1373
1374 //! Exercises the lexer by printing out the value of every token produced by the
1375 //! lexer. It is assumed that the lexer object has already be configured to read
1376 //! from some input file. The method will return when the lexer has exhausted all
1377 //! tokens, or an error occurs.
1378 void ConversionController::testLexer(ElftosbLexer & lexer)
1379 {
1380         // test lexer
1381         while (1)
1382         {
1383                 YYSTYPE value;
1384                 int lexresult = lexer.yylex();
1385                 if (lexresult == 0)
1386                         break;
1387                 lexer.getSymbolValue(&value);
1388                 Log::log("%d -> int:%d, ast:%p", lexresult, value.m_int, value.m_str, value.m_ast);
1389                 if (lexresult == TOK_IDENT || lexresult == TOK_SOURCE_NAME || lexresult == TOK_STRING_LITERAL)
1390                 {
1391                         if (value.m_str)
1392                         {
1393                                 Log::log(", str:%s\n", value.m_str->c_str());
1394                         }
1395                         else
1396                         {
1397                                 Log::log("str:NULL\n");
1398                         }
1399                 }
1400                 else
1401                 {
1402                         Log::log("\n");
1403                 }
1404         }
1405 }
1406
1407 //! Prints out the value of an integer constant expression AST node. Also prints
1408 //! the name of the identifier associated with that node, as well as the integer
1409 //! size.
1410 void ConversionController::printIntConstExpr(const std::string & ident, IntConstExprASTNode * expr)
1411 {
1412         // print constant value
1413         char sizeChar;
1414         switch (expr->getSize())
1415         {
1416                 case kWordSize:
1417                         sizeChar = 'w';
1418                         break;
1419                 case kHalfWordSize:
1420                         sizeChar = 'h';
1421                         break;
1422                 case kByteSize:
1423                         sizeChar = 'b';
1424                         break;
1425         }
1426         Log::log("%s => %d:%c\n", ident.c_str(), expr->getValue(), sizeChar);
1427 }
1428