Skip to content

How to identify and substitute variables that are used in expressions in C code?  #228

@vini-fda

Description

@vini-fda

I want to transform static global variables into function arguments for functions that use said variables. For example:

static int n;

int f(int x) {
    return x*x + n;
}


int main() {
    return 0;
}

Would get converted to:

int f(int x, int n) {
    return x*x + n;
}


int main() {
    return 0;
}

This is the code that I came up with in an attempt to perform the transformation:

#include <iostream>
#include "rose.h"

using namespace std;
using namespace SageBuilder;
using namespace SageInterface;

int main(int argc, char **argv)
{
    ROSE_INITIALIZE;
    SgProject *project = frontend(argc, argv);
    ROSE_ASSERT(project != NULL);

    // Traverse the AST to identify global variables
    auto nodes = NodeQuery::querySubTree(project, V_SgInitializedName);
    for (auto it = nodes.begin(); it != nodes.end(); ++it) {
        SgInitializedName *var = isSgInitializedName(*it);

        // Check if the variable is global and static
        if (isSgGlobal(var->get_scope()) && var->get_storageModifier().isStatic()) {
            auto funcDefs = NodeQuery::querySubTree(project, V_SgFunctionDefinition);
            for (auto fd : funcDefs) {
                SgFunctionDefinition* funcDef = isSgFunctionDefinition(fd);
                if (funcDef == NULL)
                    continue;
                if (funcDef->get_body()->lookup_variable_symbol(var->get_name()) == NULL) {
                     continue; // Skip if variable is not mentioned in function
                 }
                // Substitute the global variable with a parameter in the function signature
                SgFunctionParameterList *params = funcDef->get_declaration()->get_parameterList();
                SgInitializedName *param = buildInitializedName(var->get_name(), var->get_type());
                params->append_arg(param);
                // Replace all references to the original variable with the new parameter
                auto refs = NodeQuery::querySubTree(funcDef->get_body(), V_SgVarRefExp);
                for (auto refIt = refs.begin(); refIt != refs.end(); ++refIt) {
                    SgVarRefExp *varRef = isSgVarRefExp(*refIt);
                    if (varRef->get_symbol() == var->search_for_symbol_from_symbol_table()) {
                        SgVariableSymbol *paramSymbol = isSgVariableSymbol(param->search_for_symbol_from_symbol_table());
                        ROSE_ASSERT(paramSymbol != NULL);
                        varRef->set_symbol(paramSymbol);
                        // What else?
                    }
                }
            }
        }
    }

    return backend(project);
}

Unfortunately, my solution does not work. Some mistakes that I could identify:

  • The condition if (funcDef->get_body()->lookup_variable_symbol(var->get_name()) == NULL) doesn't work, because it does not traverse the AST searching for uses of the variable
  • The part where I attempt to set the symbol in the varRef is not enough. The varRef should completely change to be a reference to the new variable in the local scope of the function

I searched the documentation and the tutorials for this information but I still haven't found what I need to do the desired transformation. Any tips?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions