Eclipse CDT: Modify and save AST - c++

I'm exploring ways to alter the AST of a C/C++ code (e.g., rename a node, add a new variable) and apply these changes to the source file.
I did a lot of reading here in SO and in Eclipse forums. However I didn't find a minimal working example.
It seems that the correct way to make changes in an AST is by using the ASTRewrite class.
A similar question was asked in SO a few months ago, but it is still pending.
Here is where I'm stuck at the moment:
//get the factory
INodeFactory nodeFactory = myAST.getASTNodeFactory();
//create a new function declarator
IASTNode n = nodeFactory.newFunctionDeclarator(nodeFactory.newName("testMe"));
//get the rewriter
ASTRewrite rewriter = ASTRewrite.create(mainAST);
//replace node with n, node is not null
rewriter.replace(node, n, null);
//make the changes
Change c = rewriter.rewriteAST();
c.perform(new NullProgressMonitor());
When I run this code snippet, I get a
java.lang.NoClassDefFoundError: org/eclipse/ltk/core/refactoring/Change
Any hints are appreciated.

Related

AbortFormatting exception while modifing the ast node

In short, while I tried to modify AST, the eclipse cdt gives me org.eclipse.cdt.internal.formatter.AbortFormatting, Code sample:
for ( IASTNode node : nodes) {
rewriter.replace(node, node.copy(), null);
}
Change change = rewriter.rewriteAST();
change = change.perform(new NullProgressMonitor());
this simple code just replace a node with a same copy of it, just for sake of testing, some nodes replaced successuflly and other gives me this exception
org.eclipse.cdt.internal.formatter.AbortFormatting: [1783/54] Unexpected token type, expecting:23, actual:Token type=1 image =IdleTime offset=89705
I have been struggling for a while to know the reason and how to solve it but with no luck

Free Marker Template processing want to know data model vs Template variable missing

Can anyone help me about Free Marker Template reading process.
I want to know the missing variables in template when compared to data model which i am getting from database in Map.
Configuration cfg = new Configuration(Configuration.VERSION_2_3_24);
cfg.setDirectoryForTemplateLoading(new File(filepath));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
Map confMap = new HashMap();
confMap.put("user", "Sunil");
Template temp = cfg.getTemplate("template.txt");
OutputStream os = new FileOutputStream(filepath + "\\template.conf");
Writer out = new OutputStreamWriter(os);
temp.process(confMap, out);
template.txt
user=${user}
firstname =${firstname}
lastname =${lastname}
Am using the above mentioned code. want to know before process the template that data model vs template.
What data-model variables the template needs only turns out as the template executes. That's because of #if-s, .vars[dynamicName]-s, etc. Also it's not always obvious that if you have a ${x} then x refers to a data-model variable, or there will be an x in another scope (like a global variable) at that point.
You could still do a pretty good guess if you walk the tree of the template though. You can start that with Tempalte.getRootTreeNode(). As you will see it's a deprecated API, because backward compatibility is not promised, but it's actually unlikely to have changes in 2.3.x that would break existing code, as far as the code tries to walk the tree with as few assumptions as possible.

Error - Cannot access display string yet for new node creation in Omnet

I am trying to create a node at run time in my module in Omnet. I am able to create it with this code and its working fine.
cModule* parentmod = getParentModule();
cModule* grantParentMod = parentmod->getParentModule();
cModule* grantParentMod1 = grantParentMod->getParentModule();
// To check if the module is already created
for (cSubModIterator iter(*grantParentMod1); !iter.end(); iter++)
{
EV << iter()->getFullName()<<endl;
if (iter()->getFullName() == "host_send4")
return;
}
cModuleType *meshnode1 = cModuleType::get("inet.networklayer.manetrouting.PASER.meshnode");
cModule *mod = meshnode1->create("host_send4", grantParentMod1);
cDisplayString& dispstr = getDisplayString();
dispstr.parse("p=1000,535;r=200,green");
mod->finalizeParameters();
mod->buildInside();
mod->scheduleStart(simTime()+2*beaconInterval);
However this module is not generated at desired place in simulation output (the coordinates and the display). I believe the display string created here is not attached to the module and hence I tried to do it by this :-
cDisplayString& dispstr = getDisplayString();
dispstr.parse("p=1000,535;r=200,green");
mod->getDisplayString().set(dispstr);
But with this I encounter following error at run time :- Cannot access display string yet: Parameters not yet set up . I know the problem is in mod->getDisplayString().set(dispstr);
So is there any other way to assign the parameter or am I doing some minor error.
Thanks for this help.
Make sure you are following the module creation procedure as given in the OMNeT++ manual.
If you navigate to the The Detailed Procedure sub-section you will notice a comprehensive list which tells what step should be performed where:
Find the factory object;
Create the module;
Set up its parameters and gate sizes as needed;
Tell the (possibly compound) module to recursively create its internal submodules and connections;
Schedule activation message(s) for the new simple module(s).
Step 3 I believe is the one you are looking for. Little below is given a detailed explanation of what should be done for step 3:
If you want to set up parameter values or gate vector sizes (Step
3.), the code goes between the create() and buildInside() calls:
// create
cModuleType *moduleType = cModuleType::get("foo.nodes.WirelessNode");
cModule *module = moduleType->create("node", this);
// set up parameters and gate sizes before we set up its submodules
module->par("address") = ++lastAddress;
module->finalizeParameters();
module->setGateSize("in", 3);
module->setGateSize("out", 3);
// create internals, and schedule it
module->buildInside();
module->scheduleStart(simTime());
Be aware of the usage of the module->par("<parameter_name>") function.
PS: I was writing my answer, and in meanwhile you answered your own question. This answer can be left there for future reference, if useful.
Well I modified the code as :-
cModuleType *meshnode1 = cModuleType::get("inet.networklayer.manetrouting.PASER.meshnode");
cModule *mod = meshnode1->create("host_send4", grantParentMod1);
mod->finalizeParameters();
std::string displayString = "p=1000,535;r=200,green;i=device/smallrouter";
mod->getDisplayString().parse(displayString.c_str());
mod->buildInside();
mod->scheduleStart(simTime()+2*beaconInterval);
and then its working perfect. According to my understanding, I should add mod->finalizeParameters(); before changing the display setting and display string should be a simple string but not the cDisplayString object.

Node creation or apperance at run time in Omnet (INET)

I need to create a node at run time, with similar parameters as the other nodes. For that I am creating a dynamic node in ned file as:-
host_send4: meshnode {
parameters:
#dynamic;
#display("p=1000,535;r=200,green;i=device/smallrouter");
}
To implement this node in C++ file, I add this code:-
cModuleType *meshnode1 = cModuleType::get("inet.networklayer.manetrouting.PASER.meshnode");
cModule *mod = meshnode1->createScheduleInit("host_send4", this);
cDisplayString& dispstr = mod->getDisplayString();
dispstr.parse("p=1000,535;r=200,green;i=device/smallrouter");
mod->buildInside();
mod->scheduleStart(simTime()+5*beaconInterval);
But I am not able to build it properly. I think I am in need of any example on this. Can anybody help me to point out an example in INETMANET of mixim or any other oment framework, where this functionality is already implemented.
Thanks for your help.
I have also though of creating a node statically, which would appear in simulation at later point of time. Is it possible and is there any example with runtime appearance and disappearance of node in INET or other OMNET framework.
The OMNeT++ User Manual has a section dedicated to this. According to this you don't need buildInside() and scheduleStart() when using createScheduleInit().
An example how this is performed can be seen in the Veins framework - more precisely in the TraCIScenarioManager. The important lines for you are probably:
cModule* parentmod = getParentModule();
if (!parentmod) error("Parent Module not found");
cModuleType* nodeType = cModuleType::get(type.c_str());
if (!nodeType) error("Module Type \"%s\" not found", type.c_str());
cModule* mod = nodeType->create(name.c_str(), parentmod, nodeVectorIndex, nodeVectorIndex);
mod->finalizeParameters();
mod->getDisplayString().parse(displayString.c_str());
mod->buildInside();
mod->scheduleStart(simTime() + updateInterval);

Xerces, xpaths, and XML namespaces

I'm trying to use xerces-c in order to parse a rather massive XML document generated from StarUML in order to change some things, but I'm running into issues getting the xpath query to work because it keeps crashing.
To simplify things I split out part of the file into a smaller XML file for testing, which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<XPD:UNIT xmlns:XPD="http://www.staruml.com" version="1">
<XPD:HEADER>
<XPD:SUBUNITS>
</XPD:SUBUNITS>
</XPD:HEADER>
<XPD:BODY>
<XPD:OBJ name="Attributes[3]" type="UMLAttribute" guid="onMjrHQ0rUaSkyFAWtLzKwAA">
<XPD:ATTR name="StereotypeName" type="string">ConditionInteraction</XPD:ATTR>
</XPD:OBJ>
</XPD:BODY>
</XPD:UNIT>
All I'm trying to do for this example is to find all of the XPD:OBJ elements, of which there is only one. The problem seems to stem from trying to query with the namespace. When I pass a very simple xpath query of XPD:OBJ it will crash, but if I pass just OBJ it won't crash but it won't find the XPD:OBJ element.
I assume there's some important property or setting that I'm missing during initialization that I need to set but I have no idea what it might be. I looked up all of the properties of the parser having to do with namespace and enabled the ones I could but it didn't help at all so I'm completely stuck. The initialization code looks something like this, with lots of things removed obviously:
const tXercesXMLCh tXMLManager::kDOMImplementationFeatures[] =
{
static_cast<tXercesXMLCh>('L'),
static_cast<tXercesXMLCh>('S'),
static_cast<tXercesXMLCh>('\0')
};
// Instantiate the DOM parser.
fImplementation = static_cast<tXercesDOMImplementationLS *>(tXercesDOMImplementationRegistry::getDOMImplementation(kDOMImplementationFeatures));
if (fImplementation != nullptr)
{
fParser = fImplementation->createLSParser(tXercesDOMImplementationLS::MODE_SYNCHRONOUS, nullptr);
fConfig = fParser->getDomConfig();
// Let the validation process do its datatype normalization that is defined in the used schema language.
//fConfig->setParameter(tXercesXMLUni::fgDOMDatatypeNormalization, true);
// Ignore comments and whitespace so we don't get extra nodes to process that just waste time.
fConfig->setParameter(tXercesXMLUni::fgDOMComments, false);
fConfig->setParameter(tXercesXMLUni::fgDOMElementContentWhitespace, false);
// Setup some properties that look like they might be required to get namespaces to work but doesn't seem to help at all.
fConfig->setParameter(tXercesXMLUni::fgXercesUseCachedGrammarInParse, true);
fConfig->setParameter(tXercesXMLUni::fgDOMNamespaces, true);
fConfig->setParameter(tXercesXMLUni::fgDOMNamespaceDeclarations, true);
// Install our custom error handler.
fConfig->setParameter(tXercesXMLUni::fgDOMErrorHandler, &fErrorHandler);
}
Then later on I parse the document, find the root node, and then run the xpath query to find the node I want. I'll leave out the bulk of that and just show you where I'm running the xpath query in case there's something obviously wrong there:
tXercesDOMDocument * doc; // Comes from parsing the file.
tXercesDOMNode * contextNode; // This is the root node retrieved from the document.
tXercesDOMXPathResult * xPathResult;
doc->evaluate("XPD:OBJ", contextNode, nullptr, tXercesDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE), xPathResult);
The call to evaluate() is where it crashes somewhere deep inside xerces that I can't see very clearly, but from what I can see there are a lot of things that look deleted or uninitialized so I'm not sure what's causing the crash exactly.
So is there anything here that looks obviously wrong or missing that is required to make xerces work with XML namespaces?
The solution was right in front of my face the whole time. The problem was that you need to create and pass a resolver to the evaluate() call or else it will not be able to figure out any of the namespaces and will throw an exception. The crash seems to be a bug in xerces since it's crashing on trying to throw the exception when it can't resolve the namespace. I had to debug deep into the xerces code to find it, which gave me the solution.
So to fix the problem I changed the call to evaluate() slightly to create a resolver with the root node and now it works perfectly:
tXercesDOMDocument * doc; // Comes from parsing the file.
tXercesDOMNode * contextNode; // This is the root node retrieved from the document.
tXercesDOMXPathResult * xPathResult;
// Create the resolver with the root node, which contains the namespace definition.
tXercesDOMXPathNSResolver * resolver(doc->createNSResolver(contextNode));
doc->evaluate("XPD:OBJ", contextNode, resolver, tXercesDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE), xPathResult);
// Make sure to release the resolver since anything created from a `create___()`
// function has to be manually released.
resolver->release();