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 |
---|---|
XML. |
|
JSON. |
|
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.
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.