Parsers

The core of the framework offers four parsers.

All the parsers implement the ParserI interface. Three of the parsers implement the ConfigurationParserI interface and are capable of transforming an input stream, encoded in any of the supported languages, into a ConfigurationDatabase. One parser is capable of transforming a mathematical expression into stack machine instruction to be used by RuntimeEvaluator.

Type

Meaning

StandardParser

The MARTe configuration language.

XmlParser

XML.

JsonParser

JSON.

MathExpressionParser

Mathematical expressions.

MARTe configuration language

The MARTe configuration language has a syntax similar to JSON and is parsed using the StandardParser.

The syntax is composed by a tree of name/value pairs separated by an = sign. Curly braces are used to define multi-dimensional arrays and to create new named nodes in the tree.

An example of a configuration file using the MARTe language:

A = {
   B = 1
   C = "ABCD"
   D = {1, 2, 3, 4}
   E = {"A", "B"}
   F = {
      G = 3.34
      H = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}
   }
}

Examples

The following example shows how to parse configuration files in all the supported languages.

Object configuration example (ConfigurationExample3)
  1/**
  2 * @file ConfigurationExample3.cpp
  3 * @brief Source file for class ConfigurationExample3
  4 * @date 14/03/2018
  5 * @author Andre' Neto
  6 *
  7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
  8 * the Development of Fusion Energy ('Fusion for Energy').
  9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
 11 * You may not use this work except in compliance with the Licence.
 12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 13 *
 14 * @warning Unless required by applicable law or agreed to in writing, 
 15 * software distributed under the Licence is distributed on an "AS IS"
 16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 17 * or implied. See the Licence permissions and limitations under the Licence.
 18
 19 * @details This source file contains the definition of all the methods for
 20 * the class ConfigurationExample3 (public, protected, and private). Be aware that some
 21 * methods, such as those inline could be defined on the header file, instead.
 22 */
 23
 24#define DLL_API
 25
 26/*---------------------------------------------------------------------------*/
 27/*                         Standard header includes                          */
 28/*---------------------------------------------------------------------------*/
 29
 30/*---------------------------------------------------------------------------*/
 31/*                         Project header includes                           */
 32/*---------------------------------------------------------------------------*/
 33#include "AdvancedErrorManagement.h"
 34#include "ClassRegistryDatabase.h"
 35#include "ConfigurationDatabase.h"
 36#include "ErrorLoggerExample.h"
 37#include "JsonParser.h"
 38#include "Matrix.h"
 39#include "Object.h"
 40#include "Reference.h"
 41#include "ReferenceT.h"
 42#include "StandardParser.h"
 43#include "StreamString.h"
 44#include "Vector.h"
 45#include "XMLParser.h"
 46
 47/*---------------------------------------------------------------------------*/
 48/*                           Static definitions                              */
 49/*---------------------------------------------------------------------------*/
 50
 51/*---------------------------------------------------------------------------*/
 52/*                           Method definitions                              */
 53/*---------------------------------------------------------------------------*/
 54namespace MARTe2Tutorial {
 55
 56/**
 57 * Configuration structures
 58 */
 59struct Gains {
 60	MARTe::float32 gain1;
 61	MARTe::float32 gain2;
 62};
 63
 64struct Waveforms {
 65	MARTe::float32 *times;
 66	MARTe::float32 *values;
 67};
 68
 69/**
 70 * @brief A MARTe::Object class will be automatically registered into the ClassRegistryDatabase.
 71 */
 72class ControllerEx1: public MARTe::Object {
 73public:
 74	CLASS_REGISTER_DECLARATION()
 75
 76	/**
 77	 * @brief NOOP.
 78	 */
 79ControllerEx1	() {
 80		slowWaveform.times = NULL;
 81		slowWaveform.values = NULL;
 82		fastWaveform.times = NULL;
 83		fastWaveform.values = NULL;
 84
 85	}
 86
 87	virtual ~ControllerEx1 () {
 88		if (slowWaveform.times != NULL) {
 89			delete [] slowWaveform.times;
 90		}
 91		if (slowWaveform.values != NULL) {
 92			delete [] slowWaveform.values;
 93		}
 94		if (fastWaveform.times != NULL) {
 95			delete [] fastWaveform.times;
 96		}
 97		if (fastWaveform.values != NULL) {
 98			delete [] fastWaveform.values;
 99		}
100		if (GetName() != NULL) {
101			REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "No more references pointing at"
102					" %s [%s]. The Object will be safely deleted.", GetName(), GetClassProperties()->GetName());
103		}
104	}
105
106	/**
107	 * Read all the properties which are organised inside a tree
108	 * Gains = {
109	 *     Low = {
110	 *         Gain1 = -1.0;
111	 *         Gain2 = -3.0;
112	 *     }
113	 *     High = {
114	 *         Gain1 = 7.0;
115	 *         Gain2 = 9.0;
116	 *     }
117	 * }
118	 * References = {
119	 *     Slow = {
120	 *         Waveform = {
121	 *             Times  = {0 0.1 0.2 1}
122	 *             Values = {1 2   3   4}
123	 *         }
124	 *     }
125	 *     Fast = {
126	 *         Waveform = {
127	 *             Times  = {0 0.1 0.2 1}
128	 *             Values = {1 2   3   4}
129	 *         }
130	 *     }
131	 * }
132	 */
133	virtual bool Initialise(MARTe::StructuredDataI &data) {
134		using namespace MARTe;
135		bool ok = Object::Initialise(data);
136		if (ok) {
137			//Move in the tree
138			ok = data.MoveRelative("Gains");
139			if (!ok) {
140				REPORT_ERROR(ErrorManagement::ParametersError, "Could not move to the Gains section");
141			}
142		}
143		if (ok) {
144			ok = data.MoveRelative("Low");
145			if (!ok) {
146				REPORT_ERROR(ErrorManagement::ParametersError, "Could not move to the Gains.Low section");
147			}
148		}
149		if (ok) {
150			ok = data.Read("Gain1", lowGains.gain1);
151			if (ok) {
152				REPORT_ERROR(ErrorManagement::Information, "Gains.Low.Gain1 = %f", lowGains.gain1);
153			}
154			else {
155				REPORT_ERROR(ErrorManagement::ParametersError, "Could not read the Gains.Low.Gain1");
156			}
157		}
158		if (ok) {
159			ok = data.Read("Gain2", lowGains.gain2);
160			if (ok) {
161				REPORT_ERROR(ErrorManagement::Information, "Gains.Low.Gain2 = %f", lowGains.gain2);
162			}
163			else {
164				REPORT_ERROR(ErrorManagement::ParametersError, "Could not read the Gains.Low.Gain2");
165			}
166		}
167		if (ok) {
168			ok = data.MoveToAncestor(1u);
169			if (!ok) {
170				REPORT_ERROR(ErrorManagement::ParametersError, "Could not move back to the Gains section");
171			}
172		}
173		if (ok) {
174			ok = data.MoveRelative("High");
175			if (!ok) {
176				REPORT_ERROR(ErrorManagement::ParametersError, "Could not move to the Gains.High section");
177			}
178		}
179		if (ok) {
180			ok = data.Read("Gain1", highGains.gain1);
181			if (ok) {
182				REPORT_ERROR(ErrorManagement::Information, "Gains.High.Gain1 = %f", highGains.gain1);
183			}
184			else {
185				REPORT_ERROR(ErrorManagement::ParametersError, "Could not read the Gains.High.Gain1");
186			}
187		}
188		if (ok) {
189			ok = data.Read("Gain2", highGains.gain2);
190			if (ok) {
191				REPORT_ERROR(ErrorManagement::Information, "Gains.High.Gain2 = %f", highGains.gain2);
192			}
193			else {
194				REPORT_ERROR(ErrorManagement::ParametersError, "Could not read the Gains.High.Gain2");
195			}
196		}
197		if (ok) {
198			//Move to the ancestor
199			ok = data.MoveToAncestor(2u);
200			if (!ok) {
201				REPORT_ERROR(ErrorManagement::ParametersError, "Could not move back to the References section");
202			}
203		}
204		if (ok) {
205			ok = data.MoveRelative("References.Slow.Waveform");
206			if (!ok) {
207				REPORT_ERROR(ErrorManagement::ParametersError, "Could not move to the References.Slow.Waveform section");
208			}
209		}
210		if (ok) {
211			ok = ReadArray(data, "Times", slowWaveform.times);
212		}
213		if (ok) {
214			ok = ReadArray(data, "Values", slowWaveform.values);
215		}
216		//Move back to the parent
217		if (ok) {
218			ok = data.MoveToAncestor(2u);
219		}
220		if (ok) {
221			ok = data.MoveRelative("Fast.Waveform");
222			if (!ok) {
223				REPORT_ERROR(ErrorManagement::ParametersError, "Could not move to the References.fast.Waveform section");
224			}
225		}
226		if (ok) {
227			ok = ReadArray(data, "Times", fastWaveform.times);
228		}
229		if (ok) {
230			ok = ReadArray(data, "Values", fastWaveform.values);
231		}
232
233		return ok;
234	}
235
236private:
237	bool ReadArray(MARTe::StructuredDataI &data, const MARTe::char8 * const arrayName, MARTe::float32 *&dest) {
238		using namespace MARTe;
239		if (dest != NULL) {
240			delete [] dest;
241		}
242
243		AnyType arrayDescription = data.GetType(arrayName);
244		bool ok = arrayDescription.GetDataPointer() != NULL_PTR(void *);
245		uint32 numberOfElements = 0u;
246		if (ok) {
247			numberOfElements = arrayDescription.GetNumberOfElements(0u);
248			ok = (numberOfElements > 0u);
249			if (!ok) {
250				REPORT_ERROR(ErrorManagement::ParametersError, "No elements defined in the array with name %s", arrayName);
251			}
252		}
253		if (ok) {
254			dest = new float32[numberOfElements];
255			Vector<float32> readVector(dest, numberOfElements);
256			ok = data.Read(arrayName, readVector);
257			if (ok) {
258				REPORT_ERROR(ErrorManagement::Information, "Array set to %f", readVector);
259			}
260			else {
261				REPORT_ERROR(ErrorManagement::ParametersError, "Could not read the array with name %s", arrayName);
262			}
263		}
264		return ok;
265	}
266
267	/**
268	 * A list of properties.
269	 */
270	Gains lowGains;
271	Gains highGains;
272	Waveforms slowWaveform;
273	Waveforms fastWaveform;
274};
275
276CLASS_REGISTER(ControllerEx1, "")
277
278}
279
280//Loads a given StructuredDataI
281void Load(MARTe::ConfigurationDatabase &cdb) {
282	using namespace MARTe;
283	using namespace MARTe2Tutorial;
284
285	REPORT_ERROR_STATIC(ErrorManagement::Information,
286			"Successfully parsed CFG configuration %s", cdb);
287	//After the printf the tree is again pointing at the last leaf
288	cdb.MoveToRoot();
289	CCString className1 = "ControllerEx1";
290	ReferenceT<ControllerEx1> ref1(className1,
291			GlobalObjectsDatabase::Instance()->GetStandardHeap());
292	//Automatically generate a new object instance based on the class name and on the correct Heap and with the template reference.
293
294	if (ref1.IsValid()) {
295		ref1->SetName("ControllerInstance1");
296		REPORT_ERROR_STATIC(ErrorManagement::Information,
297				"Successfully created an instance of %s", className1.GetList());
298		cdb.MoveToRoot();
299		if (ref1->Initialise(cdb)) {
300			REPORT_ERROR_STATIC(ErrorManagement::Information,
301					"Successfully configured instance of %s", ref1->GetName());
302		} else {
303			REPORT_ERROR_STATIC(ErrorManagement::FatalError,
304					"Failed to configure instance of %s", ref1->GetName());
305		}
306	}
307}
308
309void LoadCfg() {
310	using namespace MARTe;
311	using namespace MARTe2Tutorial;
312
313	//Parse the configuration using the standard parser
314	StreamString configurationCfg = ""
315			"Gains = {\n"
316			"    Low = {\n"
317			"        Gain1 = -1.0\n"
318			"        Gain2 = -3.0\n"
319			"    }\n"
320			"    High = {\n"
321			"        Gain1 = 7.0\n"
322			"        Gain2 = 9.0\n"
323			"    }\n"
324			"}\n"
325			"References = {\n"
326			"    Slow = {\n"
327			"        Waveform = {\n"
328			"            Times  = {0 0.1 0.2 1}\n"
329			"            Values = {1 2   3   4}\n"
330			"        }\n"
331			"    }\n"
332			"    Fast = {\n"
333			"        Waveform = {\n"
334			"            Times  = {0 0.1 0.2 1}\n"
335			"            Values = {1 2   3   4}\n"
336			"        }\n"
337			"    }\n"
338			"}\n";
339
340	ConfigurationDatabase cdb;
341	StreamString err;
342	REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
343	//Force the string to be seeked to the beginning.
344	configurationCfg.Seek(0LLU);
345	StandardParser parser(configurationCfg, cdb, &err);
346	bool ok = parser.Parse();
347	if (ok) {
348		//After parsing the tree is pointing at the last leaf
349		cdb.MoveToRoot();
350		Load(cdb);
351	} else {
352		StreamString errPrint;
353		errPrint.Printf("Failed to parse %s", err.Buffer());
354		REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
355				errPrint.Buffer());
356	}
357}
358
359void LoadXml() {
360	using namespace MARTe;
361	using namespace MARTe2Tutorial;
362
363	//Parse the configuration using the XML parser
364	StreamString configurationXml = ""
365			"<Gains>\n"
366			"    <Low>\n"
367			"        <Gain1>-1.0</Gain1>\n"
368			"        <Gain2>-3.0</Gain2>\n"
369			"    </Low>\n"
370			"    <High>\n"
371			"        <Gain1>7.0</Gain1>\n"
372			"        <Gain2>9.0</Gain2>\n"
373			"    </High>\n"
374			"</Gains>\n"
375			"<References>\n"
376			"    <Slow>\n"
377			"        <Waveform>\n"
378			"            <Times>{0 0.1 0.2 1}</Times>\n"
379			"            <Values>{1 2   3  4}</Values>\n"
380			"        </Waveform>\n"
381			"    </Slow>\n"
382			"    <Fast>\n"
383			"        <Waveform>\n"
384			"            <Times>{0 0.1 0.2 1}</Times>\n"
385			"            <Values>{1 2   3  4}</Values>\n"
386			"        </Waveform>\n"
387			"    </Fast>\n"
388			"</References>\n";
389
390	ConfigurationDatabase cdb;
391	StreamString err;
392	REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading XML:\n%s", configurationXml.Buffer());
393	//Force the string to be seeked to the beginning.
394	configurationXml.Seek(0LLU);
395	XMLParser parser(configurationXml, cdb, &err);
396	bool ok = parser.Parse();
397	if (ok) {
398		//After parsing the tree is pointing at the last leaf
399		cdb.MoveToRoot();
400		Load(cdb);
401	} else {
402		StreamString errPrint;
403		errPrint.Printf("Failed to parse %s", err.Buffer());
404		REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
405				errPrint.Buffer());
406	}
407}
408
409void LoadJson() {
410	using namespace MARTe;
411	using namespace MARTe2Tutorial;
412
413	//Parse the configuration using the JSON parser
414	StreamString configurationJson = ""
415			"\"Gains\": {\n"
416			"   \"Low\": {\n"
417			"      \"Gain1\": \"-1.0\",\n"
418			"      \"Gain2\": \"-3.0\"\n"
419			"   },\n"
420			"   \"High\": {\n"
421			"      \"Gain1\": \"7.0\",\n"
422			"      \"Gain2\": \"9.0\"\n"
423			"   }\n"
424			"},\n"
425			"\"References\": {\n"
426			"   \"Slow\": {\n"
427			"       \"Waveform\": {\n"
428			"           \"Times\": [0, 0.1, 0.2, 1],\n"
429			"           \"Values\": [1, 2, 3, 4]\n"
430			"        }\n"
431			"   },\n"
432			"   \"Fast\": {\n"
433			"       \"Waveform\": {\n"
434			"           \"Times\": [0, 0.5, 1],\n"
435			"           \"Values\": [1, 0, 1]\n"
436			"        }\n"
437			"   }\n"
438			"}\n";
439	REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading Json:\n%s", configurationJson.Buffer());
440	ConfigurationDatabase cdb;
441	StreamString err;
442	//Force the string to be seeked to the beginning.
443	configurationJson.Seek(0LLU);
444	JsonParser parser(configurationJson, cdb, &err);
445	bool ok = parser.Parse();
446	if (ok) {
447		//After parsing the tree is pointing at the last leaf
448		cdb.MoveToRoot();
449		Load(cdb);
450	} else {
451		StreamString errPrint;
452		errPrint.Printf("Failed to parse %s", err.Buffer());
453		REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
454				errPrint.Buffer());
455	}
456}
457
458int main(int argc, char **argv) {
459	SetErrorProcessFunction(&ErrorProcessExampleFunction);
460	LoadCfg();
461	LoadXml();
462	LoadJson();
463	return 0;
464}

Instructions on how to compile and execute the example can be found here.