ROSE 0.11.145.147
AST Construction

AST construction is a fundamental operation needed for building ROSE source-to-source translators.

Several levels of interfaces are available in ROSE for users to build AST from scratch. High-level interfaces are recommended whenever possible for their simplicity. Low-level interfaces can give users maximum freedom to manipulate details in AST trees.

This tutorial demonstrates how to create AST fragments for common language constructs (such as variable declarations, functions, function calls, etc.) and how to insert them into an existing AST tree.

Variable Declarations

Example 1: High-Level Variable Declaration

Building a variable declaration using the high-level AST construction and manipulation interfaces defined in the SageBuilder and SageInterface namespaces.

1// SageBuilder contains all high level buildXXX() functions,
2// such as buildVariableDeclaration(), buildLabelStatement() etc.
3// SageInterface contains high level AST manipulation and utility functions,
4// e.g. appendStatement(), lookupFunctionSymbolInParentScopes() etc.
5#include "rose.h"
6using namespace SageBuilder;
7using namespace SageInterface;
8
9class SimpleInstrumentation:public SgSimpleProcessing
10{
11public:
12 void visit (SgNode * astNode);
13};
14
15void
16SimpleInstrumentation::visit (SgNode * astNode)
17{
18 SgBasicBlock *block = isSgBasicBlock (astNode);
19 if (block != NULL)
20 {
21 SgVariableDeclaration *variableDeclaration =
22 buildVariableDeclaration ("newVariable", buildIntType ());
23 prependStatement (variableDeclaration, block);
24 }
25}
26
27int
28main (int argc, char *argv[])
29{
30 // Initialize and check compatibility. See Rose::initialize
31 ROSE_INITIALIZE;
32
33 SgProject *project = frontend (argc, argv);
34 ROSE_ASSERT (project != NULL);
35
36 SimpleInstrumentation treeTraversal;
37 treeTraversal.traverseInputFiles (project, preorder);
38
39 AstTests::runAllTests (project);
40 return backend (project);
41}
virtual void visit(SgNode *astNode)=0
this method is called at every traversed node.
This class represents the concept of a block (not a basic block from control flow analysis).
This class represents the base class for all IR nodes within Sage III.
This class represents a source project, with a list of SgFile objects and global information about th...
This class represents the concept of a C or C++ variable declaration.
Functions that build an AST.
Definition sageBuilder.h:32
Functions that are useful when operating on the AST.
Definition sageBuilder.h:25

The high-level construction builds a variable declaration node using buildVariableDeclaration() and inserts it into the AST with prependStatement(). Scope pointers, symbol tables, and source file position information are handled transparently.

Example 2: Low-Level Variable Declaration

Building the variable declaration using low-level member functions of SAGE III node classes. The low-level approach requires manual handling of scope, parent pointers, and symbol tables.

1// ROSE is a tool for building preprocessors, this file is an example preprocessor built with ROSE.
2// Specifically it shows the design of a transformation to instrument source code, placing source code
3// at the top and bottom of each basic block.
4// Member functions of SAGE III AST node classes are directly used.
5// So all details for Sg_File_Info, scope, parent, symbol tables have to be explicitly handled.
6
7#include "rose.h"
8
9class SimpleInstrumentation : public SgSimpleProcessing
10 {
11 public:
12 void visit ( SgNode* astNode );
13 };
14
15void
16SimpleInstrumentation::visit ( SgNode* astNode )
17 {
18 SgBasicBlock* block = isSgBasicBlock(astNode);
19 if (block != NULL)
20 {
21 // Mark this as a transformation (required)
23 ROSE_ASSERT(sourceLocation != NULL);
24
25 SgType* type = new SgTypeInt();
26 ROSE_ASSERT(type != NULL);
27
28 SgName name = "newVariable";
29
30 SgVariableDeclaration* variableDeclaration = new SgVariableDeclaration(sourceLocation,name,type);
31 ROSE_ASSERT(variableDeclaration != NULL);
32
33 SgInitializedName* initializedName = *(variableDeclaration->get_variables().begin());
35
36 // DQ (6/18/2007): The unparser requires that the scope be set (for name qualification to work).
37 initializedName->set_scope(block);
38
39 // Liao (2/13/2008): AstTests requires this to be set
40 variableDeclaration->set_firstNondefiningDeclaration(variableDeclaration);
41
42 ROSE_ASSERT(block->get_statements().size() > 0);
43
44 block->get_statements().insert(block->get_statements().begin(),variableDeclaration);
45 variableDeclaration->set_parent(block);
46
47 // Add a symbol to the sybol table for the new variable
48 SgVariableSymbol* variableSymbol = new SgVariableSymbol(initializedName);
49 block->insert_symbol(name,variableSymbol);
50 }
51 }
52
53int
54main ( int argc, char * argv[] )
55 {
56 // Initialize and check compatibility. See Rose::initialize
57 ROSE_INITIALIZE;
58
59 SgProject* project = frontend(argc,argv);
60 ROSE_ASSERT(project != NULL);
61
62 SimpleInstrumentation treeTraversal;
63 treeTraversal.traverseInputFiles ( project, preorder );
64
65 AstTests::runAllTests(project);
66 return backend(project);
67 }
68
const SgStatementPtrList & get_statements() const
Returns a const STL list by reference.
void set_firstNondefiningDeclaration(SgDeclarationStatement *firstNondefiningDeclaration)
This is an access function for the SgDeclarationStatement::p_firstNondefiningDeclaration data member ...
This class represents the notion of a declared variable.
virtual void set_file_info(Sg_File_Info *X)
Access function calls set_startingConstruct(Sg_File_Info*) member function.
This class represents strings within the IR nodes.
void set_parent(SgNode *parent)
All nodes in the AST contain a reference to a parent node.
void insert_symbol(const SgName &n, SgSymbol *s)
Puts a SgSymbol object into the local symbol table.
This class represents the base class for all types.
const SgInitializedNamePtrList & get_variables() const
Access function for p_variables.
This class represents the concept of a variable name within the compiler (a shared container for the ...
This class represents the location of the code associated with the IR node in the original source cod...
static Sg_File_Info * generateDefaultFileInfoForTransformationNode()
Static function to return new Sg_File_Info object set to default values appropriate for transformatio...

Adding Expressions

A translator using the high-level AST builder interface can be used to add an assignment statement before the last statement in a main() function.

1// Expressions can be built using both bottomup (recommended ) and topdown orders.
2// Bottomup: build operands first, operation later
3// Topdown: build operation first, set operands later on.
4
5#include "rose.h"
6using namespace SageBuilder;
7using namespace SageInterface;
8
9int main (int argc, char *argv[])
10{
11 // Initialize and check compatibility. See Rose::initialize
12 ROSE_INITIALIZE;
13
14 SgProject *project = frontend (argc, argv);
15 // go to the function body
16 SgFunctionDeclaration* mainFunc= findMain(project);
17
18 SgBasicBlock* body= mainFunc->get_definition()->get_body();
19 pushScopeStack(body);
20
21 // bottomup: build operands first, create expression later on
22 // double result = 2 * (1 - gama * gama);
23 SgExpression * init_exp =
24 buildMultiplyOp(buildDoubleVal(2.0),
25 buildSubtractOp(buildDoubleVal(1.0),
26 buildMultiplyOp (buildVarRefExp("gama"),buildVarRefExp("gama")
27 )));
28 SgVariableDeclaration* decl = buildVariableDeclaration("result",buildDoubleType(),buildAssignInitializer(init_exp));
29
30 SgStatement* laststmt = getLastStatement(topScopeStack());
31 insertStatementBefore(laststmt,decl);
32
33 // topdown: build expression first, set operands later on
34 // double result2 = alpha * beta;
35 SgExpression * init_exp2 = buildMultiplyOp();
36 setLhsOperand(init_exp2,buildVarRefExp("alpha"));
37 setRhsOperand(init_exp2,buildVarRefExp("beta"));
38
39 SgVariableDeclaration* decl2 = buildVariableDeclaration("result2",buildDoubleType(),buildAssignInitializer(init_exp2));
40 laststmt = getLastStatement(topScopeStack());
41 insertStatementBefore(laststmt,decl2);
42
43 popScopeStack();
44 AstTests::runAllTests(project);
45
46 //invoke backend compiler to generate object/binary files
47 return backend (project);
48
49}
50
This class represents the notion of an expression. Expressions are derived from SgLocatedNodes,...
This class represents the concept of a function declaration statement.
SgBasicBlock * get_body() const
Access function for p_body.
This class represents the notion of a statement.

Assignment Statements

Adding an assignment statement before the last statement in a main() function using the high-level AST builder interface.

1// SageBuilder contains all high level buildXXX() functions,
2// such as buildVariableDeclaration(), buildLabelStatement() etc.
3// SageInterface contains high level AST manipulation and utility functions,
4// e.g. appendStatement(), lookupFunctionSymbolInParentScopes() etc.
5#include "rose.h"
6using namespace SageBuilder;
7using namespace SageInterface;
8
9int main (int argc, char *argv[])
10{
11 // Initialize and check compatibility. See Rose::initialize
12 ROSE_INITIALIZE;
13
14 SgProject *project = frontend (argc, argv);
15
16 // go to the function body of main()
17 // and push it to the scope stack
18 SgFunctionDeclaration* mainFunc= findMain(project);
19 SgBasicBlock* body= mainFunc->get_definition()->get_body();
20 pushScopeStack(body);
21
22 // build a variable assignment statement: i=9;
23 // buildVarRefExp(string varName) will automatically search for a matching variable symbol starting
24 // from the current scope to the global scope.
25 SgExprStatement* assignStmt = buildAssignStatement(buildVarRefExp("i"),buildIntVal(9));
26
27 // insert it before the last return statement
28 SgStatement* lastStmt = getLastStatement(topScopeStack());
29 insertStatementBefore(lastStmt,assignStmt);
30
31 popScopeStack();
32
33 //AstTests ensures there is no dangling SgVarRefExp without a mathing symbol
34 AstTests::runAllTests(project);
35 return backend (project);
36}
37
This class represents the concept of a C or C++ statement which contains a expression.

Function Declarations

Adding a function at the top of a global scope using both high-level and low-level constructions.

High-Level Function Declaration

1// This example shows how to construct a defining function (with a function body)
2// using high level AST construction interfaces.
3//
4#include "rose.h"
5using namespace SageBuilder;
6using namespace SageInterface;
7
8class SimpleInstrumentation : public SgSimpleProcessing
9 {
10 public:
11 void visit ( SgNode* astNode );
12 };
13
14void
15SimpleInstrumentation::visit ( SgNode* astNode )
16 {
17 SgGlobal* globalScope = isSgGlobal(astNode);
18 if (globalScope != NULL)
19 {
20 // ********************************************************************
21 // Create a parameter list with a parameter
22 // ********************************************************************
23 SgName var1_name = "var_name";
24 SgReferenceType *ref_type = buildReferenceType(buildIntType());
25 SgInitializedName *var1_init_name = buildInitializedName(var1_name, ref_type);
26 SgFunctionParameterList* parameterList = buildFunctionParameterList();
27 appendArg(parameterList,var1_init_name);
28
29 // *****************************************************
30 // Create a defining functionDeclaration (with a function body)
31 // *****************************************************
32 SgName func_name = "my_function";
33 SgFunctionDeclaration * func = buildDefiningFunctionDeclaration
34 (func_name, buildIntType(), parameterList,globalScope);
35 SgBasicBlock* func_body = func->get_definition()->get_body();
36
37 // ********************************************************
38 // Insert a statement in the function body
39 // *******************************************************
40
41 SgVarRefExp *var_ref = buildVarRefExp(var1_name,func_body);
42 SgPlusPlusOp *pp_expression = buildPlusPlusOp(var_ref);
43 SgExprStatement* new_stmt = buildExprStatement(pp_expression);
44
45 // insert a statement into the function body
46 prependStatement(new_stmt,func_body);
47 prependStatement(func,globalScope);
48
49 }
50 }
51
52int
53main ( int argc, char * argv[] )
54 {
55 // Initialize and check compatibility. See Rose::initialize
56 ROSE_INITIALIZE;
57
58 SgProject* project = frontend(argc,argv);
59 ROSE_ASSERT(project != NULL);
60
61 SimpleInstrumentation treeTraversal;
62 treeTraversal.traverseInputFiles ( project, preorder );
63
64 AstTests::runAllTests(project);
65 return backend(project);
66 }
This class represents the concept of a declaration list.
This class represents the concept of a namespace definition.
This class represents the variable refernece in expressions.

High-Level Function Declaration with Scope Stack

1// This example shows how to construct a defining function (with a function body)
2// using high level AST construction interfaces.
3// A scope stack is used to pass scope information implicitly to some builder functions
4#include "rose.h"
5using namespace SageBuilder;
6using namespace SageInterface;
7
8int
9main ( int argc, char * argv[] )
10 {
11 // Initialize and check compatibility. See Rose::initialize
12 ROSE_INITIALIZE;
13
14 SgProject* project = frontend(argc,argv);
15 ROSE_ASSERT(project != NULL);
16 SgGlobal *globalScope = getFirstGlobalScope (project);
17
18 //push global scope into stack
19 pushScopeStack (isSgScopeStatement (globalScope));
20
21 // Create a parameter list with a parameter
22 SgName var1_name = "var_name";
23 SgReferenceType *ref_type = buildReferenceType(buildIntType());
24 SgInitializedName *var1_init_name = buildInitializedName(var1_name, ref_type);
25 SgFunctionParameterList* parameterList = buildFunctionParameterList();
26 appendArg(parameterList,var1_init_name);
27
28 // Create a defining functionDeclaration (with a function body)
29 SgName func_name = "my_function";
30 SgFunctionDeclaration * func = buildDefiningFunctionDeclaration
31 (func_name, buildIntType(), parameterList);
32 SgBasicBlock* func_body = func->get_definition()->get_body();
33
34 // push function body scope into stack
35 pushScopeStack(isSgScopeStatement(func_body));
36
37 // build a statement in the function body
38 SgVarRefExp *var_ref = buildVarRefExp(var1_name);
39 SgPlusPlusOp *pp_expression = buildPlusPlusOp(var_ref);
40 SgExprStatement* new_stmt = buildExprStatement(pp_expression);
41
42 // insert a statement into the function body
43 appendStatement(new_stmt);
44// pop function body off the stack
45 popScopeStack();
46
47// insert the function declaration into the scope at the top of the scope stack
48 prependStatement(func);
49 popScopeStack();
50
51 AstTests::runAllTests(project);
52 return backend(project);
53 }

Low-Level Function Declaration

Function Calls

Adding function calls to instrument code using the AST string-based rewrite mechanism or the AST builder interface.

AST Builder Interface Example

1// ROSE is a tool for building preprocessors, this file is an example preprocessor built with ROSE.
2// Specifically it shows the design of a transformation to instrument source code, placing source code
3// at the top and bottom of each basic block.
4
5#include "rose.h"
6using namespace std;
7using namespace SageInterface;
8using namespace SageBuilder;
9
10class SimpleInstrumentation:public SgSimpleProcessing
11{
12public:
13 void visit (SgNode * astNode);
14};
15
16void
17SimpleInstrumentation::visit (SgNode * astNode)
18{
19 SgBasicBlock *block = isSgBasicBlock (astNode);
20 if (block != NULL)
21 {
22 const unsigned int SIZE_OF_BLOCK = 1;
23 if (block->get_statements ().size () > SIZE_OF_BLOCK)
24 {
25 SgName name1("myTimerFunctionStart");
26 // It is up to the user to link the implementations of these functions link time
27 SgFunctionDeclaration *decl_1 = buildNondefiningFunctionDeclaration
28 (name1,buildVoidType(),buildFunctionParameterList(),block);
29 ((decl_1->get_declarationModifier()).get_storageModifier()).setExtern();
30
31 SgExprStatement* callStmt_1 = buildFunctionCallStmt
32 (name1,buildVoidType(), buildExprListExp(),block);
33
34 prependStatement(callStmt_1,block);
35 prependStatement(decl_1,block);
36
37 SgName name2("myTimerFunctionEnd");
38 // It is up to the user to link the implementations of these functions link time
39 SgFunctionDeclaration *decl_2 = buildNondefiningFunctionDeclaration
40 (name2,buildVoidType(),buildFunctionParameterList(),block);
41 ((decl_2->get_declarationModifier()).get_storageModifier()).setExtern();
42
43 SgExprStatement* callStmt_2 = buildFunctionCallStmt
44 (name2,buildVoidType(), buildExprListExp(),block);
45
46 appendStatement(decl_2,block);
47 appendStatement(callStmt_2,block);
48 }
49 }
50}
51
52int
53main (int argc, char *argv[])
54{
55 // Initialize and check compatibility. See Rose::initialize
56 ROSE_INITIALIZE;
57
58 SgProject *project = frontend (argc, argv);
59 ROSE_ASSERT (project != NULL);
60
61 SimpleInstrumentation treeTraversal;
62 treeTraversal.traverseInputFiles (project, preorder);
63
64 AstTests::runAllTests (project);
65 return backend (project);
66}

Creating a 'struct' for Global Variables

This tutorial demonstrates how to repackage global variables into a struct to support Charm++. The translator also updates all references to global variables so that they reference the variables indirectly through the struct. This is a preprocessing step required to use Charm++ and AMPI.

The example uses low-level AST manipulation at the level of the IR. More concise versions using SageInterface and SageBuilder functions should be considered for high-level manipulation.

Repackaging Global Variables

The following example repackages global variables in an application into a struct.

1// ROSE is a tool for building preprocessors, this file is an example preprocessor built with ROSE.
2// Specifically it shows the design of a transformation to do a transformation specific for Charm++.
3
4#include "rose.h"
5
6using namespace std;
7
8Rose_STL_Container<SgInitializedName*>
9buildListOfGlobalVariables ( SgSourceFile* file )
10 {
11 // This function builds a list of global variables (from a SgFile).
12 assert(file != NULL);
13
14 Rose_STL_Container<SgInitializedName*> globalVariableList;
15
16 SgGlobal* globalScope = file->get_globalScope();
17 assert(globalScope != NULL);
18 Rose_STL_Container<SgDeclarationStatement*>::iterator i = globalScope->get_declarations().begin();
19 while(i != globalScope->get_declarations().end())
20 {
21 SgVariableDeclaration *variableDeclaration = isSgVariableDeclaration(*i);
22 if (variableDeclaration != NULL)
23 {
24 Rose_STL_Container<SgInitializedName*> & variableList = variableDeclaration->get_variables();
25 Rose_STL_Container<SgInitializedName*>::iterator var = variableList.begin();
26 while(var != variableList.end())
27 {
28 globalVariableList.push_back(*var);
29 var++;
30 }
31 }
32 i++;
33 }
34
35 return globalVariableList;
36 }
37
38// This function is not used, but is useful for
39// generating the list of all global variables
40Rose_STL_Container<SgInitializedName*>
41buildListOfGlobalVariables ( SgProject* project )
42 {
43 // This function builds a list of global variables (from a SgProject).
44
45 Rose_STL_Container<SgInitializedName*> globalVariableList;
46
47 const SgFilePtrList& fileList = project->get_fileList();
48 SgFilePtrList::const_iterator file = fileList.begin();
49
50 // Loop over the files in the project (multiple files exist
51 // when multiple source files are placed on the command line).
52 while(file != fileList.end())
53 {
54 Rose_STL_Container<SgInitializedName*> fileGlobalVariableList = buildListOfGlobalVariables(isSgSourceFile(*file));
55
56 // DQ (9/26/2007): Moved from std::list to std::vector
57 // globalVariableList.merge(fileGlobalVariableList);
58 globalVariableList.insert(globalVariableList.begin(),fileGlobalVariableList.begin(),fileGlobalVariableList.end());
59
60 file++;
61 }
62
63 return globalVariableList;
64 }
65
66Rose_STL_Container<SgVarRefExp*>
67buildListOfVariableReferenceExpressionsUsingGlobalVariables ( SgNode* node )
68 {
69 // This function builds a list of "uses" of variables (SgVarRefExp IR nodes) within the AST.
70
71 // return variable
72 Rose_STL_Container<SgVarRefExp*> globalVariableUseList;
73
74 // list of all variables (then select out the global variables by testing the scope)
75 Rose_STL_Container<SgNode*> nodeList = NodeQuery::querySubTree ( node, V_SgVarRefExp );
76
77 Rose_STL_Container<SgNode*>::iterator i = nodeList.begin();
78 while(i != nodeList.end())
79 {
80 SgVarRefExp *variableReferenceExpression = isSgVarRefExp(*i);

Referencing Global Variables via Struct (Part 2)

This part shows the continuation of the repackaging of global variables into a struct.

1 assert(variableReferenceExpression != NULL);
2
3 assert(variableReferenceExpression->get_symbol() != NULL);
4 assert(variableReferenceExpression->get_symbol()->get_declaration() != NULL);
5 assert(variableReferenceExpression->get_symbol()->get_declaration()->get_scope() != NULL);
6
7 // Note that variableReferenceExpression->get_symbol()->get_declaration() returns the
8 // SgInitializedName (not the SgVariableDeclaration where it was declared)!
9 SgInitializedName* variable = variableReferenceExpression->get_symbol()->get_declaration();
10
11 SgScopeStatement* variableScope = variable->get_scope();
12
13 // Check if this is a variable declared in global scope, if so, then save it
14 if (isSgGlobal(variableScope) != NULL)
15 {
16 globalVariableUseList.push_back(variableReferenceExpression);
17 }
18 i++;
19 }
20
21 return globalVariableUseList;
22 }
23
24
25SgClassDeclaration*
26buildClassDeclarationAndDefinition (string name, SgScopeStatement* scope)
27 {
28 // This function builds a class declaration and definition
29 // (both the defining and nondefining declarations as required).
30
31 // Build a file info object marked as a transformation
32 Sg_File_Info* fileInfo = Sg_File_Info::generateDefaultFileInfoForTransformationNode();
33 assert(fileInfo != NULL);
34
35 // This is the class definition (the fileInfo is the position of the opening brace)
36 SgClassDefinition* classDefinition = new SgClassDefinition(fileInfo);
37 assert(classDefinition != NULL);
38
39 // Set the end of construct explictly (where not a transformation this is the location of the closing brace)
40 classDefinition->set_endOfConstruct(fileInfo);
41
42 // This is the defining declaration for the class (with a reference to the class definition)
43 SgClassDeclaration* classDeclaration = new SgClassDeclaration(fileInfo,name.c_str(),SgClassDeclaration::e_struct,NULL,classDefinition);
44 assert(classDeclaration != NULL);
45
46 // Set the defining declaration in the defining declaration!
47 classDeclaration->set_definingDeclaration(classDeclaration);
48
49 // Set the non defining declaration in the defining declaration (both are required)
50 SgClassDeclaration* nondefiningClassDeclaration = new SgClassDeclaration(fileInfo,name.c_str(),SgClassDeclaration::e_struct,NULL,NULL);
51 assert(classDeclaration != NULL);
52 nondefiningClassDeclaration->set_scope(scope);
53 nondefiningClassDeclaration->set_type(SgClassType::createType(nondefiningClassDeclaration));
54
55 // Set the internal reference to the non-defining declaration
56 classDeclaration->set_firstNondefiningDeclaration(nondefiningClassDeclaration);
57 classDeclaration->set_type(nondefiningClassDeclaration->get_type());
58
59 // Set the defining and no-defining declarations in the non-defining class declaration!
60 nondefiningClassDeclaration->set_firstNondefiningDeclaration(nondefiningClassDeclaration);
61 nondefiningClassDeclaration->set_definingDeclaration(classDeclaration);
62
63 // Set the nondefining declaration as a forward declaration!
64 nondefiningClassDeclaration->setForward();
65
66 // Don't forget the set the declaration in the definition (IR node constructors are side-effect free!)!
67 classDefinition->set_declaration(classDeclaration);
68
69 // set the scope explicitly (name qualification tricks can imply it is not always the parent IR node!)
70 classDeclaration->set_scope(scope);
71
72 // some error checking
73 assert(classDeclaration->get_definingDeclaration() != NULL);
74 assert(classDeclaration->get_firstNondefiningDeclaration() != NULL);
75 assert(classDeclaration->get_definition() != NULL);
76
77 // DQ (9/8/2007): Need to add function symbol to global scope!
78 printf ("Fixing up the symbol table in scope = %p = %s for class = %p = %s \n",scope,scope->class_name().c_str(),classDeclaration,classDeclaration->get_name().str());
79 SgClassSymbol* classSymbol = new SgClassSymbol(classDeclaration);
80 scope->insert_symbol(classDeclaration->get_name(),classSymbol);

Handling Global Variables (Part 3)

The third part of the example, continuing the transformation of global variables into a struct.

1 ROSE_ASSERT(scope->lookup_class_symbol(classDeclaration->get_name()) != NULL);
2
3 return classDeclaration;
4 }
5
6
7
8SgVariableSymbol*
9putGlobalVariablesIntoClass (Rose_STL_Container<SgInitializedName*> & globalVariables, SgClassDeclaration* classDeclaration )
10 {
11 // This function iterates over the list of global variables and inserts them into the iput class definition
12
13 SgVariableSymbol* globalClassVariableSymbol = NULL;
14
15 for (Rose_STL_Container<SgInitializedName*>::iterator var = globalVariables.begin(); var != globalVariables.end(); var++)
16 {
17 // printf ("Appending global variable = %s to new globalVariableContainer \n",(*var)->get_name().str());
18 SgVariableDeclaration* globalVariableDeclaration = isSgVariableDeclaration((*var)->get_parent());
19 assert(globalVariableDeclaration != NULL);
20
21 // Get the global scope from the global variable directly
22 SgGlobal* globalScope = isSgGlobal(globalVariableDeclaration->get_scope());
23 assert(globalScope != NULL);
24
25 if (var == globalVariables.begin())
26 {
27 // This is the first time in this loop, replace the first global variable with
28 // the class declaration/definition containing all the global variables!
29 // Note that initializers in the global variable declarations require modification
30 // of the preinitialization list in the class's constructor! I am ignoring this for now!
31 globalScope->replace_statement(globalVariableDeclaration,classDeclaration);
32
33 // Build source position informaiton (marked as transformation)
34 Sg_File_Info* fileInfo = Sg_File_Info::generateDefaultFileInfoForTransformationNode();
35 assert(fileInfo != NULL);
36
37 // Add the variable of the class type to the global scope!
38 SgClassType* variableType = new SgClassType(classDeclaration->get_firstNondefiningDeclaration());
39 assert(variableType != NULL);
40 SgVariableDeclaration* variableDeclaration = new SgVariableDeclaration(fileInfo,"AMPI_globals",variableType);
41 assert(variableDeclaration != NULL);
42
43 globalScope->insert_statement(classDeclaration,variableDeclaration,false);
44
45 assert(variableDeclaration->get_variables().empty() == false);
46 SgInitializedName* variableName = *(variableDeclaration->get_variables().begin());
47 assert(variableName != NULL);
48
49 // DQ (9/8/2007): Need to set the scope of the new variable.
50 variableName->set_scope(globalScope);
51
52 // build the return value
53 globalClassVariableSymbol = new SgVariableSymbol(variableName);
54
55 // DQ (9/8/2007): Need to add the symbol to the global scope (new testing requires this).
56 globalScope->insert_symbol(variableName->get_name(),globalClassVariableSymbol);
57 ROSE_ASSERT(globalScope->lookup_variable_symbol(variableName->get_name()) != NULL);
58 }
59 else
60 {
61 // for all other iterations of this loop ...
62 // remove variable declaration from the global scope
63 globalScope->remove_statement(globalVariableDeclaration);
64 }
65
66 // add the variable declaration to the class definition
67 classDeclaration->get_definition()->append_member(globalVariableDeclaration);
68 }
69
70 return globalClassVariableSymbol;
71 }
72
73
74void
75fixupReferencesToGlobalVariables ( Rose_STL_Container<SgVarRefExp*> & variableReferenceList, SgVariableSymbol* globalClassVariableSymbol)
76 {
77 // Now fixup the SgVarRefExp to reference the global variables through a struct
78 for (Rose_STL_Container<SgVarRefExp*>::iterator var = variableReferenceList.begin(); var != variableReferenceList.end(); var++)
79 {
80 assert(*var != NULL);

Final Steps of Global Variable Repackaging (Part 4)

This part completes the transformation and repackaging of global variables into a struct.

1 // printf ("Variable reference for %s \n",(*var)->get_symbol()->get_declaration()->get_name().str());
2
3 SgNode* parent = (*var)->get_parent();
4 assert(parent != NULL);
5
6 // If this is not an expression then is likely a meaningless statement such as ("x;")
7 SgExpression* parentExpression = isSgExpression(parent);
8 assert(parentExpression != NULL);
9
10 // Build the reference through the global class variable ("x" --> "AMPI_globals.x")
11
12 // Build source position informaiton (marked as transformation)
13 Sg_File_Info* fileInfo = Sg_File_Info::generateDefaultFileInfoForTransformationNode();
14 assert(fileInfo != NULL);
15
16 // Build "AMPI_globals"
17 SgExpression* lhs = new SgVarRefExp(fileInfo,globalClassVariableSymbol);
18 assert(lhs != NULL);
19 // Build "AMPI_globals.x" from "x"
20 SgDotExp* globalVariableReference = new SgDotExp(fileInfo,lhs,*var);
21 assert(globalVariableReference != NULL);
22
23 if (parentExpression != NULL)
24 {
25 // Introduce reference to *var through the data structure
26
27 // case of binary operator
28 SgUnaryOp* unaryOperator = isSgUnaryOp(parentExpression);
29 if (unaryOperator != NULL)
30 {
31 unaryOperator->set_operand(globalVariableReference);
32 }
33 else
34 {
35 // case of binary operator
36 SgBinaryOp* binaryOperator = isSgBinaryOp(parentExpression);
37 if (binaryOperator != NULL)
38 {
39 // figure out if the *var is on the lhs or the rhs
40 if (binaryOperator->get_lhs_operand() == *var)
41 {
42 binaryOperator->set_lhs_operand(globalVariableReference);
43 }
44 else
45 {
46 assert(binaryOperator->get_rhs_operand() == *var);
47 binaryOperator->set_rhs_operand(globalVariableReference);
48 }
49 }
50 else
51 {
52 // ignore these cases for now!
53 switch(parentExpression->variantT())
54 {
55 // Where the variable appers in the function argument list the parent is a SgExprListExp
56 case V_SgExprListExp:
57 {
58 printf ("Sorry not implemented, case of global variable in function argument list ... \n");
59 ROSE_ABORT();
60 }
61 case V_SgInitializer:
62 case V_SgRefExp:
63 case V_SgVarArgOp:
64 default:
65 {
66 printf ("Error: default reached in switch parentExpression = %p = %s \n",parentExpression,parentExpression->class_name().c_str());
67 ROSE_ABORT();
68 }
69 }
70 }
71 }
72 }
73 }
74 }
75
76#define OUTPUT_NAMES_OF_GLOBAL_VARIABLES 0
77#define OUTPUT_NAMES_OF_GLOBAL_VARIABLE_REFERENCES 0
78
79void
80transformGlobalVariablesToUseStruct ( SgSourceFile *file )

Struct Usage Finalization (Part 5)

This is the final part of the global variable repackaging and struct manipulation process.

1 {
2 assert(file != NULL);
3
4 // These are the global variables in the input program (provided as helpful information)
5 Rose_STL_Container<SgInitializedName*> globalVariables = buildListOfGlobalVariables(file);
6
7#if OUTPUT_NAMES_OF_GLOBAL_VARIABLES
8 printf ("global variables (declared in global scope): \n");
9 for (Rose_STL_Container<SgInitializedName*>::iterator var = globalVariables.begin(); var != globalVariables.end(); var++)
10 {
11 printf (" %s \n",(*var)->get_name().str());
12 }
13 printf ("\n");
14#endif
15
16 // get the global scope within the first file (currently ignoring all other files)
17 SgGlobal* globalScope = file->get_globalScope();
18 assert(globalScope != NULL);
19
20 // Build the class declaration
21 SgClassDeclaration* classDeclaration = buildClassDeclarationAndDefinition("AMPI_globals_t",globalScope);
22
23 // Put the global variables intothe class
24 SgVariableSymbol* globalClassVariableSymbol = putGlobalVariablesIntoClass(globalVariables,classDeclaration);
25
26 // Their associated symbols will be located within the project's AST
27 // (where they occur in variable reference expressions).
28 Rose_STL_Container<SgVarRefExp*> variableReferenceList = buildListOfVariableReferenceExpressionsUsingGlobalVariables(file);
29
30#if OUTPUT_NAMES_OF_GLOBAL_VARIABLE_REFERENCES
31 printf ("global variables appearing in the application: \n");
32 for (Rose_STL_Container<SgVarRefExp*>::iterator var = variableReferenceList.begin(); var != variableReferenceList.end(); var++)
33 {
34 printf (" %s \n",(*var)->get_symbol()->get_declaration()->get_name().str());
35 }
36 printf ("\n");
37#endif
38
39 // Fixup all references to global variable to access the variable through the class ("x" --> "AMPI_globals.x")
40 fixupReferencesToGlobalVariables(variableReferenceList,globalClassVariableSymbol);
41 }
42
43
44void
45transformGlobalVariablesToUseStruct ( SgProject *project )
46 {
47 // Call the transformation of each file (there are multiple SgFile
48 // objects when multiple files are specfied on the command line!).
49 assert(project != NULL);
50
51 const SgFilePtrList& fileList = project->get_fileList();
52 SgFilePtrList::const_iterator file = fileList.begin();
53 while(file != fileList.end())
54 {
55 transformGlobalVariablesToUseStruct(isSgSourceFile(*file));
56 file++;
57 }
58 }
59
60// ******************************************
61// MAIN PROGRAM
62// ******************************************
63int
64main( int argc, char * argv[] )
65 {
66 // Initialize and check compatibility. See Rose::initialize
67 ROSE_INITIALIZE;
68
69 // Build the AST used by ROSE
70 SgProject* project = frontend(argc,argv);
71 assert(project != NULL);
72
73 // transform application as required
74 transformGlobalVariablesToUseStruct(project);
75
76 // Code generation phase (write out new application "rose_<input file name>")
77 return backend(project);
78 }

Example Input Code for Struct Repackaging

Example source code used as input to the translator for repackaging global variables into a struct.

1int x;
2int y;
3long z;
4float pressure;
5
6int main()
7 {
8 int a = 0;
9 int b = 0;
10 float density = 1.0;
11
12 x++;
13 b++;
14
15 x = a + y;
16
17 return 0;
18 }

Example Output of Global Variable Repackaging

The output of the input after the translator repackages the global variables into a struct.

1
2struct AMPI_globals_t
3{
4 int x;
5 int y;
6 long z;
7 float pressure;
8}
9;
10struct AMPI_globals_t AMPI_globals;
11
12int main()
13{
14 int a = 0;
15 int b = 0;
16 float density = 1.0;
17 AMPI_globals . x++;
18 b++;
19 AMPI_globals . x = a + AMPI_globals . y;
20 return 0;
21}