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.
16SimpleInstrumentation::visit (
SgNode * astNode)
22 buildVariableDeclaration (
"newVariable", buildIntType ());
23 prependStatement (variableDeclaration, block);
28main (
int argc,
char *argv[])
33 SgProject *project = frontend (argc, argv);
34 ROSE_ASSERT (project != NULL);
36 SimpleInstrumentation treeTraversal;
37 treeTraversal.traverseInputFiles (project, preorder);
39 AstTests::runAllTests (project);
40 return backend (project);
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.
Functions that are useful when operating on the AST.
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.
12 void visit (
SgNode* astNode );
16SimpleInstrumentation::visit (
SgNode* astNode )
23 ROSE_ASSERT(sourceLocation != NULL);
26 ROSE_ASSERT(type != NULL);
28 SgName name =
"newVariable";
31 ROSE_ASSERT(variableDeclaration != NULL);
37 initializedName->set_scope(block);
54main (
int argc,
char * argv[] )
60 ROSE_ASSERT(project != NULL);
62 SimpleInstrumentation treeTraversal;
63 treeTraversal.traverseInputFiles ( project, preorder );
65 AstTests::runAllTests(project);
66 return backend(project);
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.
9int main (
int argc,
char *argv[])
14 SgProject *project = frontend (argc, argv);
24 buildMultiplyOp(buildDoubleVal(2.0),
25 buildSubtractOp(buildDoubleVal(1.0),
26 buildMultiplyOp (buildVarRefExp(
"gama"),buildVarRefExp(
"gama")
28 SgVariableDeclaration* decl = buildVariableDeclaration(
"result",buildDoubleType(),buildAssignInitializer(init_exp));
30 SgStatement* laststmt = getLastStatement(topScopeStack());
31 insertStatementBefore(laststmt,decl);
36 setLhsOperand(init_exp2,buildVarRefExp(
"alpha"));
37 setRhsOperand(init_exp2,buildVarRefExp(
"beta"));
39 SgVariableDeclaration* decl2 = buildVariableDeclaration(
"result2",buildDoubleType(),buildAssignInitializer(init_exp2));
40 laststmt = getLastStatement(topScopeStack());
41 insertStatementBefore(laststmt,decl2);
44 AstTests::runAllTests(project);
47 return backend (project);
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.
9int main (
int argc,
char *argv[])
14 SgProject *project = frontend (argc, argv);
25 SgExprStatement* assignStmt = buildAssignStatement(buildVarRefExp(
"i"),buildIntVal(9));
28 SgStatement* lastStmt = getLastStatement(topScopeStack());
29 insertStatementBefore(lastStmt,assignStmt);
34 AstTests::runAllTests(project);
35 return backend (project);
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
11 void visit (
SgNode* astNode );
15SimpleInstrumentation::visit (
SgNode* astNode )
17 SgGlobal* globalScope = isSgGlobal(astNode);
18 if (globalScope != NULL)
23 SgName var1_name =
"var_name";
27 appendArg(parameterList,var1_init_name);
32 SgName func_name =
"my_function";
34 (func_name, buildIntType(), parameterList,globalScope);
41 SgVarRefExp *var_ref = buildVarRefExp(var1_name,func_body);
46 prependStatement(new_stmt,func_body);
47 prependStatement(func,globalScope);
53main (
int argc,
char * argv[] )
59 ROSE_ASSERT(project != NULL);
61 SimpleInstrumentation treeTraversal;
62 treeTraversal.traverseInputFiles ( project, preorder );
64 AstTests::runAllTests(project);
65 return backend(project);
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
9main (
int argc,
char * argv[] )
15 ROSE_ASSERT(project != NULL);
16 SgGlobal *globalScope = getFirstGlobalScope (project);
19 pushScopeStack (isSgScopeStatement (globalScope));
22 SgName var1_name =
"var_name";
26 appendArg(parameterList,var1_init_name);
29 SgName func_name =
"my_function";
31 (func_name, buildIntType(), parameterList);
35 pushScopeStack(isSgScopeStatement(func_body));
43 appendStatement(new_stmt);
48 prependStatement(func);
51 AstTests::runAllTests(project);
52 return backend(project);
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
13 void visit (
SgNode * astNode);
17SimpleInstrumentation::visit (
SgNode * astNode)
22 const unsigned int SIZE_OF_BLOCK = 1;
25 SgName name1(
"myTimerFunctionStart");
28 (name1,buildVoidType(),buildFunctionParameterList(),block);
29 ((decl_1->get_declarationModifier()).get_storageModifier()).setExtern();
32 (name1,buildVoidType(), buildExprListExp(),block);
34 prependStatement(callStmt_1,block);
35 prependStatement(decl_1,block);
37 SgName name2(
"myTimerFunctionEnd");
40 (name2,buildVoidType(),buildFunctionParameterList(),block);
41 ((decl_2->get_declarationModifier()).get_storageModifier()).setExtern();
44 (name2,buildVoidType(), buildExprListExp(),block);
46 appendStatement(decl_2,block);
47 appendStatement(callStmt_2,block);
53main (
int argc,
char *argv[])
58 SgProject *project = frontend (argc, argv);
59 ROSE_ASSERT (project != NULL);
61 SimpleInstrumentation treeTraversal;
62 treeTraversal.traverseInputFiles (project, preorder);
64 AstTests::runAllTests (project);
65 return backend (project);
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++.
8Rose_STL_Container<SgInitializedName*>
9buildListOfGlobalVariables ( SgSourceFile* file )
11 // This function builds a list of global variables (from a SgFile).
14 Rose_STL_Container<SgInitializedName*> globalVariableList;
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())
21 SgVariableDeclaration *variableDeclaration = isSgVariableDeclaration(*i);
22 if (variableDeclaration != NULL)
24 Rose_STL_Container<SgInitializedName*> & variableList = variableDeclaration->get_variables();
25 Rose_STL_Container<SgInitializedName*>::iterator var = variableList.begin();
26 while(var != variableList.end())
28 globalVariableList.push_back(*var);
35 return globalVariableList;
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 )
43 // This function builds a list of global variables (from a SgProject).
45 Rose_STL_Container<SgInitializedName*> globalVariableList;
47 const SgFilePtrList& fileList = project->get_fileList();
48 SgFilePtrList::const_iterator file = fileList.begin();
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())
54 Rose_STL_Container<SgInitializedName*> fileGlobalVariableList = buildListOfGlobalVariables(isSgSourceFile(*file));
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());
63 return globalVariableList;
66Rose_STL_Container<SgVarRefExp*>
67buildListOfVariableReferenceExpressionsUsingGlobalVariables ( SgNode* node )
69 // This function builds a list of "uses" of variables (SgVarRefExp IR nodes) within the AST.
72 Rose_STL_Container<SgVarRefExp*> globalVariableUseList;
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 );
77 Rose_STL_Container<SgNode*>::iterator i = nodeList.begin();
78 while(i != nodeList.end())
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);
3 assert(variableReferenceExpression->get_symbol() != NULL);
4 assert(variableReferenceExpression->get_symbol()->get_declaration() != NULL);
5 assert(variableReferenceExpression->get_symbol()->get_declaration()->get_scope() != NULL);
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();
11 SgScopeStatement* variableScope = variable->get_scope();
13 // Check if this is a variable declared in global scope, if so, then save it
14 if (isSgGlobal(variableScope) != NULL)
16 globalVariableUseList.push_back(variableReferenceExpression);
21 return globalVariableUseList;
26buildClassDeclarationAndDefinition (string name, SgScopeStatement* scope)
28 // This function builds a class declaration and definition
29 // (both the defining and nondefining declarations as required).
31 // Build a file info object marked as a transformation
32 Sg_File_Info* fileInfo = Sg_File_Info::generateDefaultFileInfoForTransformationNode();
33 assert(fileInfo != NULL);
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);
39 // Set the end of construct explictly (where not a transformation this is the location of the closing brace)
40 classDefinition->set_endOfConstruct(fileInfo);
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);
46 // Set the defining declaration in the defining declaration!
47 classDeclaration->set_definingDeclaration(classDeclaration);
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));
55 // Set the internal reference to the non-defining declaration
56 classDeclaration->set_firstNondefiningDeclaration(nondefiningClassDeclaration);
57 classDeclaration->set_type(nondefiningClassDeclaration->get_type());
59 // Set the defining and no-defining declarations in the non-defining class declaration!
60 nondefiningClassDeclaration->set_firstNondefiningDeclaration(nondefiningClassDeclaration);
61 nondefiningClassDeclaration->set_definingDeclaration(classDeclaration);
63 // Set the nondefining declaration as a forward declaration!
64 nondefiningClassDeclaration->setForward();
66 // Don't forget the set the declaration in the definition (IR node constructors are side-effect free!)!
67 classDefinition->set_declaration(classDeclaration);
69 // set the scope explicitly (name qualification tricks can imply it is not always the parent IR node!)
70 classDeclaration->set_scope(scope);
72 // some error checking
73 assert(classDeclaration->get_definingDeclaration() != NULL);
74 assert(classDeclaration->get_firstNondefiningDeclaration() != NULL);
75 assert(classDeclaration->get_definition() != NULL);
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);
3 return classDeclaration;
9putGlobalVariablesIntoClass (Rose_STL_Container<SgInitializedName*> & globalVariables, SgClassDeclaration* classDeclaration )
11 // This function iterates over the list of global variables and inserts them into the iput class definition
13 SgVariableSymbol* globalClassVariableSymbol = NULL;
15 for (Rose_STL_Container<SgInitializedName*>::iterator var = globalVariables.begin(); var != globalVariables.end(); var++)
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);
21 // Get the global scope from the global variable directly
22 SgGlobal* globalScope = isSgGlobal(globalVariableDeclaration->get_scope());
23 assert(globalScope != NULL);
25 if (var == globalVariables.begin())
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);
33 // Build source position informaiton (marked as transformation)
34 Sg_File_Info* fileInfo = Sg_File_Info::generateDefaultFileInfoForTransformationNode();
35 assert(fileInfo != NULL);
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);
43 globalScope->insert_statement(classDeclaration,variableDeclaration,false);
45 assert(variableDeclaration->get_variables().empty() == false);
46 SgInitializedName* variableName = *(variableDeclaration->get_variables().begin());
47 assert(variableName != NULL);
49 // DQ (9/8/2007): Need to set the scope of the new variable.
50 variableName->set_scope(globalScope);
52 // build the return value
53 globalClassVariableSymbol = new SgVariableSymbol(variableName);
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);
61 // for all other iterations of this loop ...
62 // remove variable declaration from the global scope
63 globalScope->remove_statement(globalVariableDeclaration);
66 // add the variable declaration to the class definition
67 classDeclaration->get_definition()->append_member(globalVariableDeclaration);
70 return globalClassVariableSymbol;
75fixupReferencesToGlobalVariables ( Rose_STL_Container<SgVarRefExp*> & variableReferenceList, SgVariableSymbol* globalClassVariableSymbol)
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++)
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());
3 SgNode* parent = (*var)->get_parent();
4 assert(parent != NULL);
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);
10 // Build the reference through the global class variable ("x" --> "AMPI_globals.x")
12 // Build source position informaiton (marked as transformation)
13 Sg_File_Info* fileInfo = Sg_File_Info::generateDefaultFileInfoForTransformationNode();
14 assert(fileInfo != NULL);
16 // Build "AMPI_globals"
17 SgExpression* lhs = new SgVarRefExp(fileInfo,globalClassVariableSymbol);
19 // Build "AMPI_globals.x" from "x"
20 SgDotExp* globalVariableReference = new SgDotExp(fileInfo,lhs,*var);
21 assert(globalVariableReference != NULL);
23 if (parentExpression != NULL)
25 // Introduce reference to *var through the data structure
27 // case of binary operator
28 SgUnaryOp* unaryOperator = isSgUnaryOp(parentExpression);
29 if (unaryOperator != NULL)
31 unaryOperator->set_operand(globalVariableReference);
35 // case of binary operator
36 SgBinaryOp* binaryOperator = isSgBinaryOp(parentExpression);
37 if (binaryOperator != NULL)
39 // figure out if the *var is on the lhs or the rhs
40 if (binaryOperator->get_lhs_operand() == *var)
42 binaryOperator->set_lhs_operand(globalVariableReference);
46 assert(binaryOperator->get_rhs_operand() == *var);
47 binaryOperator->set_rhs_operand(globalVariableReference);
52 // ignore these cases for now!
53 switch(parentExpression->variantT())
55 // Where the variable appers in the function argument list the parent is a SgExprListExp
58 printf ("Sorry not implemented, case of global variable in function argument list ... \n");
66 printf ("Error: default reached in switch parentExpression = %p = %s \n",parentExpression,parentExpression->class_name().c_str());
76#define OUTPUT_NAMES_OF_GLOBAL_VARIABLES 0
77#define OUTPUT_NAMES_OF_GLOBAL_VARIABLE_REFERENCES 0
80transformGlobalVariablesToUseStruct ( SgSourceFile *file )
Struct Usage Finalization (Part 5)
This is the final part of the global variable repackaging and struct manipulation process.
4 // These are the global variables in the input program (provided as helpful information)
5 Rose_STL_Container<SgInitializedName*> globalVariables = buildListOfGlobalVariables(file);
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++)
11 printf (" %s \n",(*var)->get_name().str());
16 // get the global scope within the first file (currently ignoring all other files)
17 SgGlobal* globalScope = file->get_globalScope();
18 assert(globalScope != NULL);
20 // Build the class declaration
21 SgClassDeclaration* classDeclaration = buildClassDeclarationAndDefinition("AMPI_globals_t",globalScope);
23 // Put the global variables intothe class
24 SgVariableSymbol* globalClassVariableSymbol = putGlobalVariablesIntoClass(globalVariables,classDeclaration);
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);
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++)
34 printf (" %s \n",(*var)->get_symbol()->get_declaration()->get_name().str());
39 // Fixup all references to global variable to access the variable through the class ("x" --> "AMPI_globals.x")
40 fixupReferencesToGlobalVariables(variableReferenceList,globalClassVariableSymbol);
45transformGlobalVariablesToUseStruct ( SgProject *project )
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);
51 const SgFilePtrList& fileList = project->get_fileList();
52 SgFilePtrList::const_iterator file = fileList.begin();
53 while(file != fileList.end())
55 transformGlobalVariablesToUseStruct(isSgSourceFile(*file));
60// ******************************************
62// ******************************************
64main( int argc, char * argv[] )
66 // Initialize and check compatibility. See Rose::initialize
69 // Build the AST used by ROSE
70 SgProject* project = frontend(argc,argv);
71 assert(project != NULL);
73 // transform application as required
74 transformGlobalVariablesToUseStruct(project);
76 // Code generation phase (write out new application "rose_<input file name>")
77 return backend(project);
Example Input Code for Struct Repackaging
Example source code used as input to the translator for repackaging global variables into a struct
.
Example Output of Global Variable Repackaging
The output of the input after the translator repackages the global variables into a struct
.
10struct AMPI_globals_t AMPI_globals;
19 AMPI_globals . x = a + AMPI_globals . y;