#include <mvlc/TCLConfigParser.h>
class TCLConfigParser {
public:
TCLConfigParser(const std::string& infile);
CStack* getEventStack() ;
CStack* getScalerStack();
virtual void initialize();
virtual void operator()();
CTCLInterpreter* getInterpreter();
CReadoutModule* findDevice(std::string devname);
virtual void addDevice(std::string devname, CReadoutModule* driver);
virtual void addExtensions();
virtual void addExtension(CTCLObjectProcessor& cmdobj);
void addExtension(CTCLObjectProcessor* pCmd)
static TCLConfigParser* getInstance();
};
This is the base class for the translator parser. The subclass MVLCConfigParser
does al lthe real work with this class just providing the framework on which devices, the event
and scaler stack can be hung.
In order to handle a virtual initialization of the extensions, a two phase initialization
is required. First the specific subclass must be instantiated. Next initialize
must be called. This is a virtual method that will do any type specific initialization including,
but not limited to registering extensions. Finally, when ready to interpret the configuration
script to build the final configuration, operator() should be
called to process the configuration file into a configuration. The final step, would naturally
be using that configuration to generate the final configuration file.
Note that this method is an irregular singleton in that it has a public constructor that
prevents multiple invocations and a getInstance that returns
a pointer to the singleton object if it has been constructed.
TCLConfigParser(const std::string& infile);
The constructor requires a single parameter; the path to the file that
is interpreted by operator(). Note that construction
also instantiates a CTCLInterpreter object.
The infile is saved in member data and is the name
of the configuration file that operator() will intepret.
CStack* getEventStack();
It makes sense to call this method, only after operator()
has processed the configuration file. If an event stack, has been defined
by the configuration, this method returns a pointer to it. If not,
nullptr is returned. nullptr will, naturally,
also be returned if the configuration file has not yet been processed.
CStack* getScalerStack();
It makes sense to call this method, only after operator()
has processed the configuration file. If an scaler stack, has been defined
by the configuration, this method returns a pointer to it. If not,
nullptr is returned. nullptr will, naturally,
also be returned if the configuration file has not yet been processed.
virtual void initialize();
This method invokes addExtensions to extend the
Tcl interpreter used to interpret the configuration script.
Since this operation is virtual it cannot be invoked from the constructor.
This is is because constructor code ignores the polymophism of virtual
methods. This is why the two phase construction described in
DESCRIPTION is needed to allow subclasses to do their
own type specific initialization.
Subclasses typically only need to modify addExtensions
to add the set of domain specific verbs the interpreter will understand.
virtual void operator()();
This method interprets the configuration file tha was passed in to the constructor. Once the configuration has been built from the file the code generator can query it to generate appropriate operations.
CTCLInterpreter* getInterpreter();
Returns a pointer to the interpreter object that will be used to interpret the configuration file.
CReadoutModule* findDevice(std::string devname);
It only makes sense to call this method after, or during configuration.
It returns a pointer to the CReadoutModule of the
device named devname. One use during configuration is
for devices such as caenchain,
or
stack
to validate the contents of
their list of devices they control.
DeviceCommand objects
will also use this to ensure they are not creating devices with dupliate names
and to lookup existing devices to configure or introspect their configurations.
If there is no match to the module name in the set of modules defined when
findDevice is called, a nullptr is returned.
virtual void addDevice(std::string devname, CReadoutModule* driver);
Adds a new named device driver instance wrapped together with its configuration to the configuration being buit up.
This is normally called from a
DeviceCommand
when it creates a new
CReadoutModule
to enter that device in the configuration.
devname is the name assigned to the device
in the create subcommand while driver
is a pointer to the
CReadoutModule
that subcommand created.
virtual void addExtensions();
This is an no-op method. It is not pure virtual to facilitate unit testing. Normally derived class override this method and provide code to extend the base Tcl intepreter that will be used to interpret the configuration file.
This can be thought of as a strategy method that is called by
initialize
virtual void addExtension(CTCLObjectProcessor& cmdobj);
Adds a command extension to the interpreter. The configuration maintains a List
of command objects added. cmdobj must be
dynamically created via new. Ownership passes into our object and
the object delete's all extensions added in this way
when it is destroyed.
void addExtension(CTCLObjectProcessor* pCmd);
Invokes the previous overload of addExtension with
the dereferences pCmd.
static TCLConfigParser* getInstance();
As described, this is an irregular singleton. If an instance has been created, this will return a pointer to that instance. If not, nullptr is returned. The irregularity stems from the need to pass a connfiguration file name into the constructor of the instance.