comparison host/libcdl/parse.cxx @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children 6736c52df507
comparison
equal deleted inserted replaced
75:41bf073c0c32 76:435cced73e2f
1 //{{{ Banner
2
3 //============================================================================
4 //
5 // parse.cxx
6 //
7 // Miscellaneous parsing routines
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 1999, 2000 Red Hat, Inc.
14 //
15 // This file is part of the eCos host tools.
16 //
17 // This program is free software; you can redistribute it and/or modify it
18 // under the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 of the License, or (at your option)
20 // any later version.
21 //
22 // This program is distributed in the hope that it will be useful, but WITHOUT
23 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
25 // more details.
26 //
27 // You should have received a copy of the GNU General Public License along with
28 // this program; if not, write to the Free Software Foundation, Inc.,
29 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 //
31 // ----------------------------------------------------------------------------
32 //
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
36 //
37 // Author(s): bartv
38 // Contact(s): bartv
39 // Date: 1999/02/23
40 // Version: 0.02
41 //
42 //####DESCRIPTIONEND####
43 //============================================================================
44
45 //}}}
46 //{{{ #include's
47
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
50
51 // Get the infrastructure types, assertions, tracing and similar
52 // facilities.
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
55
56 // <cdlcore.hxx> defines everything implemented in this module.
57 // It implicitly supplies <string>, <vector> and <map> because
58 // the class definitions rely on these headers.
59 #include <cdlcore.hxx>
60
61 //}}}
62
63 //{{{ Description
64
65 // ----------------------------------------------------------------------------
66 // All CDL data is read via a Tcl interpreter, so the parsing is done by
67 // procedures that appear as Tcl commands. This has obvious advantages in
68 // terms of expressive power, but does result in a little bit of confusion
69 // when producing diagnostics.
70 //
71 // Errors should not bypass the Tcl interpreter, to ensure that that
72 // stays in a consistent state. In particular it is not possible to let
73 // arbitrary C++ exceptions to go straight through the Tcl interpreter,
74 // this is likely to result in a corrupted interpreter.
75 //
76 // Also, it is not a good idea to abort parsing as soon as anything
77 // goes wrong. Instead there should be an error handling callback associated
78 // with the interpreter, which can be used to report errors. This
79 // callback may choose to raise an exception.
80 //
81 // Consider the case of parsing a property (which accounts for most of
82 // the code in this module). A property does not exist in isolation,
83 // only within the context of a suitable CDL entity such as an option.
84 // If parsing succeeds and a property object is created then it must
85 // be added to the current CDL entity.
86 //
87 // Therefore a typical parse routine looks like this:
88 //
89 // 1) get the current CDL node from the interpreter
90 // 2) do basic parsing of the data. Any errors should be reported
91 // via the callback.
92 // 3) create a suitable CdlProperty object
93 // 4) add the property to the current entity
94 //
95 // std::bad_alloc and CdlStringException exceptions can be thrown, they
96 // will be intercepted by the CdlInterpreter class.
97
98 //}}}
99 //{{{ Statics
100
101 // ----------------------------------------------------------------------------
102 // The string "property " is needed in various places. Provide it as a static
103 // to cut down the number of times the string constructor has to run.
104 static std::string property_string = "property ";
105
106 //}}}
107 //{{{ Generic parsing-related utilities
108
109 //{{{ argv manipulation
110
111 // ----------------------------------------------------------------------------
112 // Some of the properties have aliases in the CDL data, so argv[0] has to be
113 // used to work out what is actually being parsed. However the Tcl interpreter
114 // may prefix the command name with :: to indicate the global namespace.
115 const char*
116 CdlParse::get_tcl_cmd_name(const char* name)
117 {
118 if ((name[0] == ':') && (name[1] == ':')) {
119 return &(name[2]);
120 } else {
121 return name;
122 }
123 }
124
125 // Given a list of arguments, concatenate them together into a C++ string.
126 // This makes expression parsing easier. The final argument should be an
127 // index into the array, typically the result of a call to skip_argv_options().
128 std::string
129 CdlParse::concatenate_argv(int argc, char** argv, int index)
130 {
131 CYG_REPORT_FUNCNAME("CdlParse::concatenate_argv");
132
133 std::string result = "";
134 for ( int i = index ; i < argc; i++) {
135 if (i > index) {
136 result += ' ';
137 }
138 result += std::string(argv[i]);
139 }
140
141 CYG_REPORT_RETURN();
142 return result;
143 }
144
145 // ----------------------------------------------------------------------------
146 // Option parsing.
147 //
148 // Some properties accept modifiers in their argument list. For example,
149 // by default a "compile" property is just a list of source files that
150 // should be compiled and added to the current library. It is possible
151 // to specify an alternative library via a modifier:
152 //
153 // ...
154 // compile -library=libextras.a dummy.cxx
155 // ...
156 //
157 // The rules applied for such options are intended to follow common Tcl
158 // practice:
159 //
160 // 1) any initial arguments beginning with a - are assumed to be
161 // options.
162 //
163 // 2) the first argument which does not begin with a - stops option
164 // processing.
165 //
166 // 3) option processing can also be terminated with a -- argument.
167 // This may occasionally be required, e.g. to have -ve constants
168 // in an expression.
169 //
170 // 4) the parsing code does not distinguish between single and double
171 // hyphens. If there happens to be a second - in an option then this
172 // is just ignored.
173 //
174 // 5) it is not necessary to supply the whole option name, as long as
175 // what is provided is unambiguous. For example -lib=libextras.a is
176 // acceptable (for now anyway, conceivably it would break in future).
177 // Option processing is case sensitive.
178 //
179 // 6) name/value pairs can take the form -name=value or the form
180 // -name value, whichever is appropriate.
181 //
182 // The parse_options() function takes the current interpreter (so that
183 // it can generate diagnostics), a prefix such as `property
184 // "requires"' or `package CYGPKG_HAL', details of the options to be
185 // parsed, an argc/argv list, an index, and a reference to a vector.
186 // The parsed options get placed in the vector, and the index argument
187 // gets updated to point at the first non-option argument. It will
188 // report problems via report_warning().
189 //
190 // The options description consists of a pointer to an array of
191 // C strings (allowing static initialization). Passing a zero
192 // argument indicates that the property takes no options. Otherwise
193 // the array should be zero terminated.
194 //
195 // Each entry in the array takes the form "name:flags". The optional
196 // flags consist of zero or more characters indicating how the option
197 // should be interpreted. Valid flags are:
198 //
199 // f - this option takes no data, it is just a boolean flag. The
200 // default behaviour assumes name/value pairs.
201 //
202 // m - this option can occur multiple times. The default behaviour
203 // is that each option can only occur once.
204
205 // Utility function to get hold of an option name without the colon
206 // or terminating flags.
207
208 static std::string
209 get_option_string(char* name)
210 {
211 std::string result = "";
212 while ((*name != ':') && (*name != '\0')) {
213 result += *name++;
214 }
215 return result;
216 }
217
218 int
219 CdlParse::parse_options(CdlInterpreter interp, std::string diag_prefix, char** options,
220 int argc, char** argv, int index,
221 std::vector<std::pair<std::string,std::string> >& result)
222 {
223 CYG_REPORT_FUNCNAMETYPE("CdlParse::parse_options", "final index %d");
224 CYG_REPORT_FUNCARG4XV(interp, options, argc, argv);
225 CYG_PRECONDITION_CLASSC(interp);
226 CYG_PRECONDITIONC(argc > 0); // The property name must be present.
227 // It is possible for some of the arguments to have been processed already.
228 CYG_PRECONDITIONC((index > 0) && (index <= argc));
229
230 while((index < argc) && ('-' == argv[index][0])) {
231
232 std::string name = "";
233 std::string value = "";
234
235 // The sequence -- should always terminate option processing.
236 if (0 == strcmp(argv[index], "--")) {
237 index++;
238 break;
239 }
240
241 char* arg_ptr = argv[index];
242 // Skip the initial -, and the second one as well if it is present.
243 if ('-' == *++arg_ptr) {
244 arg_ptr++;
245 }
246
247 // Construct the option name. This is the current argument up
248 // to but not including the '=' character or EOD.
249 while (('=' != *arg_ptr) && ('\0' != *arg_ptr)) {
250 name += *arg_ptr++;
251 }
252
253 if ("" == name) {
254 // One of "-", "-=xxx", or "--=x"
255 CdlParse::report_warning(interp, diag_prefix + ", invalid option string " + argv[index]);
256 }
257
258 // Do not try to extract the value unless we are sure there
259 // should be one. Instead try to match the option name. The
260 // current value of name should be a unique substring of
261 // one of the known option strings.
262 //
263 // Note that the supplied options descriptor can be NULL,
264 // since most properties do not yet take any options.
265 // In that case opt_index will remain at -1, and we should
266 // get an "invalid option" diagnostic.
267 unsigned int i;
268 int opt_index = -1;
269 if (0 != options) {
270 for (i = 0; 0 != options[i]; i++) {
271 if (0 == strncmp(name.c_str(), options[i], name.size())) {
272 if (-1 != opt_index) {
273 CdlParse::report_warning(interp, diag_prefix + ", ambiguous option name " + name +
274 ", it can match " + get_option_string(options[opt_index]) +
275 " or " + get_option_string(options[i]));
276 index++;
277 break;
278 } else {
279 opt_index = i;
280 }
281 }
282 }
283 }
284 if (-1 == opt_index) {
285 CdlParse::report_warning(interp, diag_prefix + ", invalid option " + name);
286 index++;
287 break;
288 }
289
290 // The option has been identified successfully. Extract the flags.
291 bool flag_flag = false;
292 bool multiple_flag = false;
293 char* tmp = options[opt_index];
294 while (('\0' != *tmp) && (':' != *tmp)) {
295 tmp++;
296 }
297 if (':' == *tmp) {
298 do {
299 tmp++;
300 if ('f' == *tmp) {
301 flag_flag = true;
302 } else if ('m' == *tmp) {
303 multiple_flag = true;
304 } else if ('\0' != *tmp) {
305 CYG_FAIL("Invalid property option");
306 }
307 } while ('\0' != *tmp);
308 }
309
310 // We now know the full option name. Use it for future diagnostics.
311 name = get_option_string(options[opt_index]);
312
313 // Take care of the value.
314 if (flag_flag) {
315 // There should not be a value. If the current argument is of the
316 // form x=y then this is an error.
317 if ('=' == *arg_ptr) {
318 CdlParse::report_warning(interp, diag_prefix + ", option " + name + " does not take any data");
319 }
320 // Leave index pointing at the next argument to be processed.
321 index++;
322 } else {
323 if ('=' == *arg_ptr) {
324 value = std::string(++arg_ptr);
325 } else if (++index == argc) {
326 CdlParse::report_warning(interp, diag_prefix + ", missing data for option " + name);
327 } else {
328 value = argv[index];
329 }
330 index++;
331 }
332 // At this stage index points at the next argument to be processed, and should not
333 // be updated again.
334
335 // Unless the option can occur multiple times, make sure that it is not already
336 // present in the options vector.
337 if (!multiple_flag) {
338 for (i = 0; i < result.size(); i++) {
339 if (name == result[i].first) {
340 CdlParse::report_warning(interp, diag_prefix + ", option " + name +
341 " can only be used once.");
342 break;
343 }
344 }
345 }
346
347 // The name/value pair is valid, so add it to the result vector.
348 result.push_back(std::make_pair(name, value));
349 }
350
351 CYG_REPORT_RETVAL(index);
352 return index;
353 }
354
355 //}}}
356 //{{{ Diagnostic prefix
357
358 // Construct a suitable prefix for any warning or error message. This
359 // should include the filename and the entity name.
360 //
361 // Obviously a line number would be rather useful as well, but this is not
362 // very easy because of the way Tcl interpreters work.
363
364 std::string
365 CdlParse::get_diagnostic_prefix(CdlInterpreter interp)
366 {
367 std::string filename = interp->get_filename();
368 CdlNode current_node = interp->get_node();
369
370 std::string result = ("" != filename) ? filename : "<unknown data source>";
371 if (0 != current_node) {
372 result += ", " + current_node->get_class_name() + " " + current_node->get_name();
373 }
374 result += "\n ";
375 return result;
376 }
377
378 //}}}
379 //{{{ Error count tracking
380
381 // Keep track of the number of errors that have occurred while doing some
382 // parsing. This functionality is not provided directly by the CdlInterpreter
383 // class, instead it is implemented using assoc data.
384
385 static const char error_count_key[] = "CdlErrorCount";
386
387 static void
388 error_count_delproc(ClientData data, Tcl_Interp* interp)
389 {
390 CYG_REPORT_FUNCNAME("CdlParse::error_count_delproc");
391 int* newed_ptr = static_cast<int*>(data);
392 delete newed_ptr;
393 CYG_REPORT_RETURN();
394 }
395
396 void
397 CdlParse::clear_error_count(CdlInterpreter interp)
398 {
399 CYG_REPORT_FUNCNAME("CdlParse::clear_error_count");
400 CYG_REPORT_FUNCARG1("interp %p", interp);
401 CYG_PRECONDITION_CLASSC(interp);
402
403 int* newed_ptr = static_cast<int*>(interp->get_assoc_data(error_count_key));
404 if (0 != newed_ptr) {
405 *newed_ptr = 0;
406 }
407
408 CYG_REPORT_RETURN();
409 }
410
411 void
412 CdlParse::incr_error_count(CdlInterpreter interp, int how_much)
413 {
414 CYG_REPORT_FUNCNAME("CdlParse::incr_error_counter");
415 CYG_REPORT_FUNCARG2("interp %p, how_much %d", interp, how_much);
416 CYG_PRECONDITION_CLASSC(interp);
417 CYG_PRECONDITION(how_much > 0, "previous errors cannot be undone");
418
419 int* newed_ptr = static_cast<int*>(interp->get_assoc_data(error_count_key));
420 if (0 == newed_ptr) {
421 newed_ptr = new int(how_much);
422 interp->set_assoc_data(error_count_key, static_cast<void*>(newed_ptr), &error_count_delproc);
423 } else {
424 CYG_ASSERT((*newed_ptr + how_much) > *newed_ptr, "number of parsing errors should not overflow");
425 *newed_ptr += how_much;
426 }
427
428 CYG_REPORT_RETURN();
429 }
430
431 int
432 CdlParse::get_error_count(CdlInterpreter interp)
433 {
434 CYG_REPORT_FUNCNAMETYPE("CdlParse::get_error_count", "count %d");
435 CYG_REPORT_FUNCARG1("interp %p", interp);
436 CYG_PRECONDITION_CLASSC(interp);
437
438 int result = 0;
439 int* newed_ptr = static_cast<int*>(interp->get_assoc_data(error_count_key));
440 if (0 != newed_ptr) {
441 result = *newed_ptr;
442 }
443
444 CYG_REPORT_RETVAL(result);
445 return result;
446 }
447
448 //}}}
449 //{{{ Error and warning reporting
450
451 // Report an error or warning. This involves adding a suitable prefix
452 // and invoking the reporting callback currently associated with the
453 // interpreter. For errors it is also necessary to increment the error
454 // counter so that later count can detect the number of errors that
455 // have occurred.
456 //
457 // The error callback is allowed to raise a CdlParseException. This should
458 // not be caught here. Instead this exception is caught in every parse
459 // routine, before it can go back through the Tcl interpreter.
460 //
461 // FIXME: cope with prefixing multiline error messages.
462
463 void
464 CdlParse::report_error(CdlInterpreter interp, std::string message)
465 {
466 CYG_REPORT_FUNCNAME("CdlParse::report_error");
467 CYG_REPORT_FUNCARG1("interp %p", interp);
468 CYG_PRECONDITION_CLASSC(interp);
469
470 incr_error_count(interp);
471
472 message = get_diagnostic_prefix(interp) + message;
473
474 CdlDiagnosticFnPtr fn = interp->get_error_fn_ptr();
475 CYG_ASSERT(0 != fn, "during parsing an interpreter should have an associated error reporting function");
476 (*fn)(message);
477
478 CYG_REPORT_RETURN();
479 }
480
481 void
482 CdlParse::report_warning(CdlInterpreter interp, std::string message)
483 {
484 CYG_REPORT_FUNCNAME("CdlParse::report_warning");
485 CYG_REPORT_FUNCARG1("interp %p", interp);
486 CYG_PRECONDITION_CLASSC(interp);
487
488 message = get_diagnostic_prefix(interp) + message;
489 CdlDiagnosticFnPtr fn = interp->get_warning_fn_ptr();
490 if (0 != fn) {
491 (*fn)(message);
492 }
493
494 CYG_REPORT_RETURN();
495 }
496
497 //}}}
498 //{{{ The "unknown" command
499
500 // ----------------------------------------------------------------------------
501 // This routine should be installed in interpreters that get used for
502 // parsing CDL scripts. It gets invoked when the CDL script contains
503 // an unrecognised command, e.g. because of a typo, and makes sure that
504 // the usual diagnostics process is observed.
505 //
506 // This routine should be uninstalled after the parsing is complete,
507 // to avoid e.g. a ParseException when it is not expected.
508 int
509 CdlParse::unknown_command(CdlInterpreter interp, int argc, char** argv)
510 {
511 CYG_REPORT_FUNCNAME("CdlParse::unknown_command");
512 CYG_REPORT_FUNCARG3XV(interp, argc, argv);
513 CYG_PRECONDITIONC(2 <= argc);
514 CYG_PRECONDITION_CLASSC(interp);
515
516 report_error(interp, std::string("Unknown command `") + argv[1] + "'.");
517 CYG_UNUSED_PARAM(int, argc);
518
519 return TCL_OK;
520 }
521
522 //}}}
523
524 //}}}
525 //{{{ Property-related parser utilities
526
527 // ----------------------------------------------------------------------------
528 // Utilities related to parsing properties, rather than more general parsing.
529
530 // Provide a prefix that matches the current property.
531 std::string
532 CdlParse::get_property_prefix(char* argv0)
533 {
534 CYG_REPORT_FUNCNAME("CdlParse::get_property_prefix");
535
536 std::string result = std::string("Property " ) + CdlParse::get_tcl_cmd_name(argv0) + ", ";
537
538 CYG_REPORT_RETURN();
539 return result;
540 }
541
542 std::string
543 CdlParse::get_property_prefix(CdlProperty prop)
544 {
545 CYG_REPORT_FUNCNAME("CdlParse::get_property_prefix");
546
547 std::string result = std::string("Property ");
548 const std::vector<std::string>& argv = prop->get_argv();
549 result = result + argv[0] + ", ";
550
551 CYG_REPORT_RETURN();
552 return result;
553 }
554
555 // A variant of report_parse_error() which also adds the property prefix.
556 void
557 CdlParse::report_property_parse_error(CdlInterpreter interp, char* argv0, std::string msg)
558 {
559 CYG_REPORT_FUNCNAME("CdlPase::report_property_parse_error");
560
561 report_error(interp, get_property_prefix(argv0) + msg);
562
563 CYG_REPORT_RETURN();
564 }
565
566 void
567 CdlParse::report_property_parse_error(CdlInterpreter interp, CdlProperty prop, std::string msg)
568 {
569 CYG_REPORT_FUNCNAME("CdlParse::report_property_parse_error");
570
571 report_error(interp, get_property_prefix(prop) + msg);
572
573 CYG_REPORT_RETURN();
574 }
575
576 //}}}
577 //{{{ Generic property parsers
578
579 // ----------------------------------------------------------------------------
580 // Generic parsers
581 //
582 // These routines provide some more generic property parsing routines. argv[0]
583 // generally provides sufficient information to allow for sensible error messages.
584 // The command-specific parsers have to provide a property name. In addition it is
585 // possible to provide a function to handle per-command options, and another
586 // function that performs a final sanity check before the property gets added
587 // to the current entity.
588
589 //{{{ parse_minimal_property()
590
591 // ----------------------------------------------------------------------------
592 // A minimal property takes no arguments.
593
594 int
595 CdlParse::parse_minimal_property(CdlInterpreter interp, int argc, char** argv, std::string name,
596 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_Minimal))
597 {
598 CYG_REPORT_FUNCNAME("parse_minimal_property");
599 CYG_PRECONDITION_CLASSC(interp);
600
601 CdlProperty_Minimal new_property = 0;
602 try {
603 std::vector<std::pair<std::string,std::string> > options;
604 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
605
606 if (data_index < argc) {
607 CdlParse::report_property_parse_error(interp, argv[0], std::string("Unexpected data ") + argv[data_index]);
608 } else {
609
610 // The command is valid, turn it into a property.
611 // The property has been parsed successfully. Add it to the current node
612 CdlNode current_node = interp->get_node();
613 CYG_ASSERTC(0 != current_node);
614 new_property = CdlProperty_MinimalBody::make(current_node, name, argc, argv, options);
615 if (0 != final_parser) {
616 (*final_parser)(interp, new_property);
617 }
618 }
619 } catch(...) {
620
621 if (0 != new_property) {
622 delete new_property;
623 }
624 throw;
625 }
626
627 return TCL_OK;
628 }
629
630 //}}}
631 //{{{ parse_string_property()
632
633 // ----------------------------------------------------------------------------
634
635 int
636 CdlParse::parse_string_property(CdlInterpreter interp, int argc, char** argv, std::string name,
637 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_String))
638 {
639 CYG_REPORT_FUNCNAME("parse_string_property");
640 CYG_PRECONDITION_CLASSC(interp);
641
642 CdlProperty_String new_property = 0;
643
644 try {
645 std::vector<std::pair<std::string,std::string> > options;
646 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
647
648 if (data_index == argc) {
649 CdlParse::report_property_parse_error(interp, argv[0], "missing argument.");
650 } else if ((data_index + 1) < argc) {
651 CdlParse::report_property_parse_error(interp, argv[0], std::string("Too many arguments, expecting just one."));
652 } else {
653
654 CdlNode current_node = interp->get_node();
655 CYG_ASSERTC(0 != current_node);
656 new_property = CdlProperty_StringBody::make(current_node, name, argv[data_index], argc, argv, options);
657 if (0 != final_parser) {
658 (*final_parser)(interp, new_property);
659 }
660 }
661 } catch(...) {
662 if (0 != new_property) {
663 delete new_property;
664 }
665 throw;
666 }
667
668 return TCL_OK;
669 }
670
671 //}}}
672 //{{{ parse_tclcode_property()
673
674 // ----------------------------------------------------------------------------
675
676 int
677 CdlParse::parse_tclcode_property(CdlInterpreter interp, int argc, char** argv, std::string name,
678 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_TclCode))
679 {
680 CYG_REPORT_FUNCNAME("parse_tclcode_property");
681 CYG_PRECONDITION_CLASSC(interp);
682
683 CdlProperty_TclCode new_property = 0;
684 try {
685 std::vector<std::pair<std::string,std::string> > options;
686 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
687
688 if (data_index == argc) {
689 CdlParse::report_property_parse_error(interp, argv[0], "missing Tcl code.");
690 } else if ((data_index + 1) < argc) {
691 CdlParse::report_property_parse_error(interp, argv[0], std::string("Invalid number of arguments.\n") +
692 " Expecting one argument, a Tcl code fragment.");
693 } else if (!Tcl_CommandComplete(argv[data_index])) {
694 CdlParse::report_property_parse_error(interp, argv[0], "incomplete Tcl code fragment.");
695 } else {
696
697 CdlNode current_node = interp->get_node();
698 CYG_ASSERTC(0 != current_node);
699 new_property = CdlProperty_TclCodeBody::make(current_node, name, argv[data_index], argc, argv, options);
700 if (0 != final_parser) {
701 (*final_parser)(interp, new_property);
702 }
703 }
704 } catch(...) {
705 if (0 != new_property) {
706 delete new_property;
707 }
708 throw;
709 }
710
711 return TCL_OK;
712 }
713
714 //}}}
715 //{{{ parse_stringvector_property()
716
717 // ----------------------------------------------------------------------------
718
719 int
720 CdlParse::parse_stringvector_property(CdlInterpreter interp, int argc, char** argv, std::string name,
721 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_StringVector))
722 {
723 CYG_REPORT_FUNCNAME("parse_tclcode_property");
724 CYG_PRECONDITION_CLASSC(interp);
725
726 CdlProperty_StringVector new_property = 0;
727 try {
728 std::vector<std::pair<std::string,std::string> > options;
729 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
730
731 if (data_index == argc) {
732 CdlParse::report_property_parse_error(interp, argv[0], "missing arguments.");
733 } else {
734
735 // Creating the property requires a vector of strings.
736 std::vector<std::string> strings;
737 for ( ; data_index < argc; data_index++) {
738 strings.push_back(argv[data_index]);
739 }
740 CdlNode current_node = interp->get_node();
741 CYG_ASSERTC(0 != current_node);
742 new_property = CdlProperty_StringVectorBody::make(current_node, name, strings, argc, argv, options);
743 if (0 != final_parser) {
744 (*final_parser)(interp, new_property);
745 }
746 }
747 } catch(...) {
748
749 if (0 != new_property) {
750 delete new_property;
751 }
752 throw;
753 }
754
755 return TCL_OK;
756 }
757
758 //}}}
759 //{{{ parse_reference_property()
760
761 // ----------------------------------------------------------------------------
762
763 int
764 CdlParse::parse_reference_property(CdlInterpreter interp, int argc, char** argv, std::string name,
765 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_Reference),
766 CdlUpdateHandler update_handler)
767 {
768 CYG_REPORT_FUNCNAME("parse_reference_property");
769 CYG_PRECONDITION_CLASSC(interp);
770
771 CdlProperty_Reference new_property = 0;
772 try {
773 std::vector<std::pair<std::string,std::string> > options;
774 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
775
776 if (data_index == argc) {
777 CdlParse::report_property_parse_error(interp, argv[0], "missing argument.");
778 } else if ((data_index + 1) < argc) {
779 CdlParse::report_property_parse_error(interp, argv[0], "too many arguments, expecting just one.");
780 } else {
781 std::string refname = argv[data_index];
782 if (!Cdl::is_valid_cdl_name(refname)) {
783 CdlParse::report_property_parse_error(interp, argv[0], "`" + refname + "' is not a valid CDL name");
784 } else {
785 CdlNode current_node = interp->get_node();
786 CYG_ASSERTC(0 != current_node);
787 new_property = CdlProperty_ReferenceBody::make(current_node, name, refname,
788 update_handler, argc, argv, options);
789 if (0 != final_parser) {
790 (*final_parser)(interp, new_property);
791 }
792 }
793 }
794 } catch(...) {
795 if (0 != new_property) {
796 delete new_property;
797 }
798 throw;
799 }
800
801 return TCL_OK;
802 }
803
804 //}}}
805 //{{{ parse_expression_property()
806
807 // ----------------------------------------------------------------------------
808
809 int
810 CdlParse::parse_expression_property(CdlInterpreter interp, int argc, char** argv, std::string name,
811 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_Expression),
812 CdlUpdateHandler update_handler)
813 {
814 CYG_REPORT_FUNCNAME("parse_expression_property");
815 CYG_PRECONDITION_CLASSC(interp);
816
817 CdlProperty_Expression new_property = 0;
818 CdlExpression expr = 0;
819 try {
820 std::vector<std::pair<std::string,std::string> > options;
821 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
822
823 std::string all_args = CdlParse::concatenate_argv(argc, argv, data_index);
824 if ("" == all_args) {
825 CdlParse::report_property_parse_error(interp, argv[0], "missing expression data.");
826 } else {
827
828 // The CdlExpression class has its own parsing routine. This
829 // will raise an exception if there are any problems. It is
830 // desirable to catch the exception and report the error via
831 // the normal reporting mechanisms, which may allow parsing to
832 // continue.
833 try {
834 expr = CdlExpressionBody::parse(all_args);
835 } catch(CdlParseException e) {
836 CdlParse::report_property_parse_error(interp, argv[0], e.get_message());
837 }
838 if (0 != expr) {
839 CdlNode current_node = interp->get_node();
840 CYG_ASSERTC(0 != current_node);
841 new_property = CdlProperty_ExpressionBody::make(current_node, name, expr, update_handler, argc, argv, options);
842 if (0 != final_parser) {
843 (*final_parser)(interp, new_property);
844 }
845 }
846 }
847 } catch(...) {
848 if (0 != expr) {
849 delete expr;
850 }
851 if (0 != new_property) {
852 delete new_property;
853 }
854 throw;
855 }
856
857 if (0 != expr) {
858 delete expr;
859 }
860 return TCL_OK;
861 }
862
863 //}}}
864 //{{{ parse_list_expression_property()
865
866 // ----------------------------------------------------------------------------
867
868 int
869 CdlParse::parse_listexpression_property(CdlInterpreter interp, int argc, char** argv, std::string name,
870 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_ListExpression),
871 CdlUpdateHandler update_handler)
872 {
873 CYG_REPORT_FUNCNAME("parse_list_expression_property");
874 CYG_PRECONDITION_CLASSC(interp);
875
876 CdlProperty_ListExpression new_property = 0;
877 CdlListExpression expr = 0;
878 try {
879 std::vector<std::pair<std::string,std::string> > options;
880 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
881
882 std::string all_args = CdlParse::concatenate_argv(argc, argv, data_index);
883 if ("" == all_args) {
884 CdlParse::report_property_parse_error(interp, argv[0], "missing list expression data.");
885 } else {
886
887 try {
888 expr = CdlListExpressionBody::parse(all_args);
889 } catch(CdlParseException e) {
890 CdlParse::report_property_parse_error(interp, argv[0], e.get_message());
891 }
892 if (0 != expr) {
893 CdlNode current_node = interp->get_node();
894 CYG_ASSERTC(0 != current_node);
895 new_property = CdlProperty_ListExpressionBody::make(current_node, name, expr, update_handler,
896 argc, argv, options);
897 if (0 != final_parser) {
898 (*final_parser)(interp, new_property);
899 }
900 }
901 }
902 } catch(...) {
903 if (0 != expr) {
904 delete expr;
905 }
906 if (0 != new_property) {
907 delete new_property;
908 }
909 throw;
910 }
911 if (0 != expr) {
912 delete expr;
913 }
914 return TCL_OK;
915 }
916
917 //}}}
918 //{{{ parse_goalexpression_property()
919
920 // ----------------------------------------------------------------------------
921
922 int
923 CdlParse::parse_goalexpression_property(CdlInterpreter interp, int argc, char** argv, std::string name,
924 char** options_desc, void (*final_parser)(CdlInterpreter, CdlProperty_GoalExpression),
925 CdlUpdateHandler update_handler)
926 {
927 CYG_REPORT_FUNCNAMETYPE("parse_goal_expression_property", "result %d");
928 CYG_PRECONDITION_CLASSC(interp);
929
930 CdlProperty_GoalExpression new_property = 0;
931 CdlGoalExpression expr = 0;
932 try {
933 std::vector<std::pair<std::string,std::string> > options;
934 int data_index = CdlParse::parse_options(interp, property_string + argv[0], options_desc, argc, argv, 1, options);
935
936 std::string all_args = CdlParse::concatenate_argv(argc, argv, data_index);
937 if ("" == all_args) {
938 CdlParse::report_property_parse_error(interp, argv[0], "missing goal expression data.");
939 } else {
940
941 try {
942 expr = CdlGoalExpressionBody::parse(all_args);
943 } catch(CdlParseException e) {
944 CdlParse::report_property_parse_error(interp, argv[0], e.get_message());
945 }
946 if (0 != expr) {
947 CdlNode current_node = interp->get_node();
948 CYG_ASSERTC(0 != current_node);
949 new_property = CdlProperty_GoalExpressionBody::make(current_node, name, expr, update_handler,
950 argc, argv, options);
951 if (0 != final_parser) {
952 (*final_parser)(interp, new_property);
953 }
954 }
955 }
956 } catch(...) {
957
958 if (0 != expr) {
959 delete expr;
960 }
961 if (0 != new_property) {
962 delete new_property;
963 }
964 throw;
965 }
966 if (0 != expr) {
967 delete expr;
968 }
969
970 return TCL_OK;
971 }
972
973 //}}}
974
975 //}}}