Statistics
| Branch: | Revision:

root / src / nedxml / ned2.y @ 68da4f12

History | View | Annotate | Download (55.5 KB)

1 01873262 Georg Kunz
/*===============================================================
2
 * File: ned2.y
3
 *
4
 *  Grammar for OMNeT++ NED-2.
5
 *
6
 *  Author: Andras Varga
7
 *
8
 *=============================================================*/
9
10
/*--------------------------------------------------------------*
11
  Copyright (C) 1992,2005 Andras Varga
12
13
  This file is distributed WITHOUT ANY WARRANTY. See the file
14
  `license' for details on this and other legal matters.
15
*--------------------------------------------------------------*/
16
17
/* Reserved words */
18
%token IMPORT PACKAGE PROPERTY
19
%token MODULE SIMPLE NETWORK CHANNEL MODULEINTERFACE CHANNELINTERFACE
20
%token EXTENDS LIKE
21
%token TYPES PARAMETERS GATES SUBMODULES CONNECTIONS ALLOWUNCONNECTED
22
%token DOUBLETYPE INTTYPE STRINGTYPE BOOLTYPE XMLTYPE VOLATILE
23
%token INPUT_ OUTPUT_ INOUT_
24
%token IF FOR
25
%token RIGHTARROW LEFTARROW DBLARROW TO
26
%token TRUE_ FALSE_ THIS_ DEFAULT ASK CONST_ SIZEOF INDEX_ XMLDOC
27
28
/* Other tokens: identifiers, numeric literals, operators etc */
29
%token NAME INTCONSTANT REALCONSTANT STRINGCONSTANT CHARCONSTANT
30
%token PLUSPLUS DOUBLEASTERISK
31
%token EQ NE GE LE
32
%token AND OR XOR NOT
33
%token BIN_AND BIN_OR BIN_XOR BIN_COMPL
34
%token SHIFT_LEFT SHIFT_RIGHT
35
36
%token EXPRESSION_SELECTOR   /* forces parsing text as a single expression */
37
38
%token INVALID_CHAR   /* just to generate parse error */
39
40
/* Operator precedences (low to high) and associativity */
41
%right '?' ':'
42
%left OR
43
%left XOR
44
%left AND
45
%left EQ NE '>' GE '<' LE
46
%left BIN_OR
47
%left BIN_XOR
48
%left BIN_AND
49
%left SHIFT_LEFT SHIFT_RIGHT
50
%left '+' '-'
51
%left '*' '/' '%'
52
%right '^'
53
%left UMIN NOT BIN_COMPL
54
55
%start startsymbol
56
57
/* requires at least bison 1.50 (tested with bison 2.1) */
58
%glr-parser
59
60
/* A note about parser error recovery. We only add error recovery rules to
61
 * toplevel elements. Attempting to add such rules to inner nonterminals (param, gate,
62
 * submodule, etc) has caused erratic behaviour when the synchronizing token
63
 * (";" or "}") was missing from the input, because bison executed pretty
64
 * much random rules during recovery. (For example, if a ";" is missing then the
65
 * parser may eat up everything into the middle of the next compound module where
66
 * it finally founds a ";" to synchronize on, and starts shifting tokens on the
67
 * stack from there, and matches them to rules applicable in that context).
68
 *
69
 * The actions in this grammar assume that they're being executed in the order
70
 * prescribed by the grammar, and don't tolerate that rather random behaviour
71
 * during which bison recovers from various parse errors.
72
 */
73
74
%{
75
76
#include <stdio.h>
77
#include <stdlib.h>
78
#include <stack>
79
#include "nedyydefs.h"
80
#include "nederror.h"
81
#include "nedexception.h"
82
#include "commonutil.h"
83
84
#define YYDEBUG 1           /* allow debugging */
85
#define YYDEBUGGING_ON 0    /* turn on/off debugging */
86
87
#if YYDEBUG != 0
88
#define YYERROR_VERBOSE     /* more detailed error messages */
89
#include <string.h>         /* YYVERBOSE needs it */
90
#endif
91
92
/* increase GLR stack -- with the default 200 some NED files have reportedly caused a "memory exhausted" error */
93
#define YYINITDEPTH 500
94
95
#define yylloc ned2yylloc
96
#define yyin ned2yyin
97
#define yyout ned2yyout
98
#define yyrestart ned2yyrestart
99
#define yy_scan_string ned2yy_scan_string
100
#define yy_delete_buffer ned2yy_delete_buffer
101
extern FILE *yyin;
102
extern FILE *yyout;
103
struct yy_buffer_state;
104
struct yy_buffer_state *yy_scan_string(const char *str);
105
void yy_delete_buffer(struct yy_buffer_state *);
106
void yyrestart(FILE *);
107
int yylex();
108
void yyerror (const char *s);
109
110
#include "nedparser.h"
111
#include "nedfilebuffer.h"
112
#include "nedelements.h"
113
#include "nedutil.h"
114
#include "nedyylib.h"
115
116
USING_NAMESPACE
117
118
static struct NED2ParserState
119
{
120
    bool inTypes;
121
    bool inConnGroup;
122
    std::stack<NEDElement *> propertyscope; // top(): where to insert properties as we parse them
123
    std::stack<NEDElement *> blockscope;    // top(): where to insert parameters, gates, etc
124
    std::stack<NEDElement *> typescope;     // top(): as blockscope, but ignore submodules and connection channels
125
126
    /* tmp flags, used with param, gate and conn */
127
    int paramType;
128
    int gateType;
129
    bool isVolatile;
130
    bool isDefault;
131
    YYLTYPE exprPos;
132
    int subgate;
133
    std::vector<NEDElement *> propvals; // temporarily collects property values
134
135
    /* tmp flags, used with msg fields */
136
    bool isAbstract;
137
    bool isReadonly;
138
139
    /* NED-II: modules, channels */
140
    NedFileElement *nedfile;
141
    CommentElement *comment;
142
    PackageElement *package;
143
    ImportElement *import;
144
    PropertyDeclElement *propertydecl;
145
    ExtendsElement *extends;
146
    InterfaceNameElement *interfacename;
147
    NEDElement *component;  // compound/simple module, module interface, channel or channel interface
148
    ParametersElement *parameters;
149
    ParamElement *param;
150
    PropertyElement *property;
151
    PropertyKeyElement *propkey;
152
    TypesElement *types;
153
    GatesElement *gates;
154
    GateElement *gate;
155
    SubmodulesElement *submods;
156
    SubmoduleElement *submod;
157
    ConnectionsElement *conns;
158
    ConnectionGroupElement *conngroup;
159
    ConnectionElement *conn;
160
    ChannelSpecElement *chanspec;
161
    LoopElement *loop;
162
    ConditionElement *condition;
163
} ps;
164
165
166
static void resetParserState()
167
{
168
    static NED2ParserState cleanps;
169
    ps = cleanps;
170
}
171
172
static NED2ParserState globalps;  // for error recovery
173
174
static void restoreGlobalParserState()  // for error recovery
175
{
176
    ps = globalps;
177
}
178
179
static void assertNonEmpty(std::stack<NEDElement *>& somescope)
180
{
181
    // for error recovery: STL stack::top() crashes if stack is empty
182
    if (somescope.empty())
183
    {
184
        INTERNAL_ERROR0(NULL, "error during parsing: scope stack empty");
185
        somescope.push(NULL);
186
    }
187
}
188
189
%}
190
191
%%
192
193
/*
194
 * Start rule. Support parsing a standalone expression as well
195
 */
196
startsymbol
197
        : EXPRESSION_SELECTOR expression
198
        | nedfile
199
        ;
200
201
/*
202
 * Top-level components
203
 */
204
nedfile
205
        : definitions
206
        |
207
        ;
208
209
definitions
210
        : definitions definition
211
        | definition
212
        ;
213
214
definition
215
        : packagedeclaration
216
        | import
217
        | propertydecl
218
        | fileproperty
219
        | channeldefinition
220
        | channelinterfacedefinition
221
        | simplemoduledefinition
222
        | compoundmoduledefinition
223
        | networkdefinition
224
        | moduleinterfacedefinition
225
        | ';'
226
227
        | channelinterfaceheader error '}'
228
                { storePos(ps.component, @$); restoreGlobalParserState(); }
229
        | CHANNELINTERFACE error '}'
230
                { restoreGlobalParserState(); }
231
        | simplemoduleheader error '}'
232
                { storePos(ps.component, @$); restoreGlobalParserState(); }
233
        | SIMPLE error '}'
234
                { restoreGlobalParserState(); }
235
        | compoundmoduleheader error '}'
236
                { storePos(ps.component, @$); restoreGlobalParserState(); }
237
        | MODULE error '}'
238
                { restoreGlobalParserState(); }
239
        | networkheader error '}'
240
                { storePos(ps.component, @$); restoreGlobalParserState(); }
241
        | NETWORK error '}'
242
                { restoreGlobalParserState(); }
243
        | moduleinterfaceheader error '}'
244
                { storePos(ps.component, @$); restoreGlobalParserState(); }
245
        | MODULEINTERFACE error '}'
246
                { restoreGlobalParserState(); }
247
        | channelheader error '}'
248
                { storePos(ps.component, @$); restoreGlobalParserState(); }
249
        | CHANNEL error '}'
250
                { restoreGlobalParserState(); }
251
        ;
252
253
packagedeclaration
254
        : PACKAGE dottedname ';'
255
                {
256
                  ps.package = (PackageElement *)createElementWithTag(NED_PACKAGE, ps.nedfile);
257
                  ps.package->setName(removeSpaces(@2).c_str());
258
                  storePos(ps.package,@$);
259
                  storeBannerAndRightComments(ps.package,@$);
260
                }
261
        ; /* no error recovery rule -- see discussion at top */
262
263
dottedname
264
        : dottedname '.' NAME
265
        | NAME
266
        ;
267
268
/*
269
 * Import
270
 */
271
import
272
        : IMPORT importspec ';'
273
                {
274
                  ps.import = (ImportElement *)createElementWithTag(NED_IMPORT, ps.nedfile);
275
                  ps.import->setImportSpec(removeSpaces(@2).c_str());
276
                  storePos(ps.import,@$);
277
                  storeBannerAndRightComments(ps.import,@$);
278
                }
279
        ; /* no error recovery rule -- see discussion at top */
280
281
importspec
282
        : importspec '.' importname
283
        | importname
284
        ;
285
286
importname
287
        : importname NAME
288
        | importname '*'
289
        | importname DOUBLEASTERISK
290
        | NAME
291
        | '*'
292
        | DOUBLEASTERISK
293
        ;
294
295
/*
296
 * Property declaration
297
 */
298
propertydecl
299
        : propertydecl_header opt_inline_properties ';'
300
                {
301
                    storePos(ps.propertydecl, @$);
302
                    storeBannerAndRightComments(ps.propertydecl,@$);
303
                }
304
        | propertydecl_header '(' opt_propertydecl_keys ')' opt_inline_properties ';'
305
                {
306
                    storePos(ps.propertydecl, @$);
307
                    storeBannerAndRightComments(ps.propertydecl,@$);
308
                }
309
        ; /* no error recovery rule -- see discussion at top */
310
311
propertydecl_header
312
        : PROPERTY '@' NAME
313
                {
314
                  ps.propertydecl = (PropertyDeclElement *)createElementWithTag(NED_PROPERTY_DECL, ps.nedfile);
315
                  ps.propertydecl->setName(toString(@3));
316
                }
317
        | PROPERTY '@' NAME '[' ']'
318
                {
319
                  ps.propertydecl = (PropertyDeclElement *)createElementWithTag(NED_PROPERTY_DECL, ps.nedfile);
320
                  ps.propertydecl->setName(toString(@3));
321
                  ps.propertydecl->setIsArray(true);
322
                }
323
        ;
324
325
opt_propertydecl_keys
326
        : propertydecl_keys
327
        |
328
        ;
329
330
propertydecl_keys
331
        : propertydecl_keys ';' propertydecl_key
332
        | propertydecl_key
333
        ;
334
335
propertydecl_key
336
        : NAME
337
                {
338
                  ps.propkey = (PropertyKeyElement *)createElementWithTag(NED_PROPERTY_KEY, ps.propertydecl);
339
                  ps.propkey->setName(toString(@1));
340
                  storePos(ps.propkey, @$);
341
                }
342
        ;
343
344
/*
345
 * File Property
346
 */
347
fileproperty
348
        : property_namevalue ';'
349
                {
350
                  storePos(ps.property, @$);
351
                  storeBannerAndRightComments(ps.property,@$);
352
                }
353
        ;
354
355
/*
356
 * Channel
357
 */
358
channeldefinition
359
        : channelheader '{'
360
                {
361
                  ps.typescope.push(ps.component);
362
                  ps.blockscope.push(ps.component);
363
                  ps.parameters = (ParametersElement *)createElementWithTag(NED_PARAMETERS, ps.component);
364
                  ps.parameters->setIsImplicit(true);
365
                  ps.propertyscope.push(ps.parameters);
366
                }
367
            opt_paramblock
368
          '}'
369
                {
370
                  ps.propertyscope.pop();
371
                  ps.blockscope.pop();
372
                  ps.component = ps.typescope.top();
373
                  ps.typescope.pop();
374
                  if (np->getStoreSourceFlag())
375
                      storeComponentSourceCode(ps.component, @$);
376
                  storePos(ps.component, @$);
377
                  storeTrailingComment(ps.component,@$);
378
                }
379
        ;
380
381
channelheader
382
        : CHANNEL NAME
383
                {
384
                  ps.component = (ChannelElement *)createElementWithTag(NED_CHANNEL, ps.inTypes ? (NEDElement *)ps.types : (NEDElement *)ps.nedfile);
385
                  ((ChannelElement *)ps.component)->setName(toString(@2));
386
                }
387
           opt_inheritance
388
                { storeBannerAndRightComments(ps.component,@$); }
389
        ;
390
391
opt_inheritance
392
        :
393
        | EXTENDS extendsname
394
        | LIKE likenames
395
        | EXTENDS extendsname LIKE likenames
396
        ;
397
398
extendsname
399
        : dottedname
400
                {
401
                  ps.extends = (ExtendsElement *)createElementWithTag(NED_EXTENDS, ps.component);
402
                  ps.extends->setName(removeSpaces(@1).c_str());
403
                  storePos(ps.extends, @$);
404
                }
405
        ;
406
407
likenames
408
        : likenames ',' likename
409
        | likename
410
        ;
411
412
likename
413
        : dottedname
414
                {
415
                  ps.interfacename = (InterfaceNameElement *)createElementWithTag(NED_INTERFACE_NAME, ps.component);
416
                  ps.interfacename->setName(removeSpaces(@1).c_str());
417
                  storePos(ps.interfacename, @$);
418
                }
419
        ;
420
421
/*
422
 * Channel Interface
423
 */
424
channelinterfacedefinition
425
        : channelinterfaceheader '{'
426
                {
427
                  ps.typescope.push(ps.component);
428
                  ps.blockscope.push(ps.component);
429
                  ps.parameters = (ParametersElement *)createElementWithTag(NED_PARAMETERS, ps.component);
430
                  ps.parameters->setIsImplicit(true);
431
                  ps.propertyscope.push(ps.parameters);
432
                }
433
            opt_paramblock
434
          '}'
435
                {
436
                  ps.propertyscope.pop();
437
                  ps.blockscope.pop();
438
                  ps.component = ps.typescope.top();
439
                  ps.typescope.pop();
440
                  if (np->getStoreSourceFlag())
441
                      storeComponentSourceCode(ps.component, @$);
442
                  storePos(ps.component, @$);
443
                  storeTrailingComment(ps.component,@$);
444
                }
445
        ;
446
447
channelinterfaceheader
448
        : CHANNELINTERFACE NAME
449
                {
450
                  ps.component = (ChannelInterfaceElement *)createElementWithTag(NED_CHANNEL_INTERFACE, ps.inTypes ? (NEDElement *)ps.types : (NEDElement *)ps.nedfile);
451
                  ((ChannelInterfaceElement *)ps.component)->setName(toString(@2));
452
                }
453
           opt_interfaceinheritance
454
                { storeBannerAndRightComments(ps.component,@$); }
455
        ;
456
457
opt_interfaceinheritance
458
        : EXTENDS extendsnames
459
        |
460
        ;
461
462
extendsnames
463
        : extendsnames ',' extendsname
464
        | extendsname
465
        ;
466
467
/*
468
 * Simple module
469
 */
470
simplemoduledefinition
471
        : simplemoduleheader '{'
472
                {
473
                  ps.typescope.push(ps.component);
474
                  ps.blockscope.push(ps.component);
475
                  ps.parameters = (ParametersElement *)createElementWithTag(NED_PARAMETERS, ps.component);
476
                  ps.parameters->setIsImplicit(true);
477
                  ps.propertyscope.push(ps.parameters);
478
                }
479
            opt_paramblock
480
            opt_gateblock
481
          '}'
482
                {
483
                  ps.propertyscope.pop();
484
                  ps.blockscope.pop();
485
                  ps.component = ps.typescope.top();
486
                  ps.typescope.pop();
487
                  if (np->getStoreSourceFlag())
488
                      storeComponentSourceCode(ps.component, @$);
489
                  storePos(ps.component, @$);
490
                  storeTrailingComment(ps.component,@$);
491
                }
492
        ;
493
494
simplemoduleheader
495
        : SIMPLE NAME
496
                {
497
                  ps.component = (SimpleModuleElement *)createElementWithTag(NED_SIMPLE_MODULE, ps.inTypes ? (NEDElement *)ps.types : (NEDElement *)ps.nedfile );
498
                  ((SimpleModuleElement *)ps.component)->setName(toString(@2));
499
                }
500
          opt_inheritance
501
                { storeBannerAndRightComments(ps.component,@$); }
502
        ;
503
504
/*
505
 * Module
506
 */
507
compoundmoduledefinition
508
        : compoundmoduleheader '{'
509
                {
510
                  ps.typescope.push(ps.component);
511
                  ps.blockscope.push(ps.component);
512
                  ps.parameters = (ParametersElement *)createElementWithTag(NED_PARAMETERS, ps.component);
513
                  ps.parameters->setIsImplicit(true);
514
                  ps.propertyscope.push(ps.parameters);
515
                }
516
            opt_paramblock
517
            opt_gateblock
518
            opt_typeblock
519
            opt_submodblock
520
            opt_connblock
521
          '}'
522
                {
523
                  ps.propertyscope.pop();
524
                  ps.blockscope.pop();
525
                  ps.component = ps.typescope.top();
526
                  ps.typescope.pop();
527
                  if (np->getStoreSourceFlag())
528
                      storeComponentSourceCode(ps.component, @$);
529
                  storePos(ps.component, @$);
530
                  storeTrailingComment(ps.component,@$);
531
                }
532
        ;
533
534
compoundmoduleheader
535
        : MODULE NAME
536
                {
537
                  ps.component = (CompoundModuleElement *)createElementWithTag(NED_COMPOUND_MODULE, ps.inTypes ? (NEDElement *)ps.types : (NEDElement *)ps.nedfile );
538
                  ((CompoundModuleElement *)ps.component)->setName(toString(@2));
539
                }
540
          opt_inheritance
541
                { storeBannerAndRightComments(ps.component,@$); }
542
        ;
543
544
/*
545
 * Network
546
 */
547
networkdefinition
548
        : networkheader '{'
549
                {
550
                  ps.typescope.push(ps.component);
551
                  ps.blockscope.push(ps.component);
552
                  ps.parameters = (ParametersElement *)ps.component->getFirstChildWithTag(NED_PARAMETERS); // networkheader already created it for @isNetwork
553
                  ps.parameters->setIsImplicit(true);
554
                  ps.propertyscope.push(ps.parameters);
555
                }
556
            opt_paramblock
557
            opt_gateblock
558
            opt_typeblock
559
            opt_submodblock
560
            opt_connblock
561
          '}'
562
                {
563
                  ps.propertyscope.pop();
564
                  ps.blockscope.pop();
565
                  ps.component = ps.typescope.top();
566
                  ps.typescope.pop();
567
                  if (np->getStoreSourceFlag())
568
                      storeComponentSourceCode(ps.component, @$);
569
                  storePos(ps.component, @$);
570
                  storeTrailingComment(ps.component,@$);
571
                }
572
        ;
573
574
networkheader
575
        : NETWORK NAME
576
                {
577
                  ps.component = (CompoundModuleElement *)createElementWithTag(NED_COMPOUND_MODULE, ps.inTypes ? (NEDElement *)ps.types : (NEDElement *)ps.nedfile );
578
                  ((CompoundModuleElement *)ps.component)->setName(toString(@2));
579
                }
580
          opt_inheritance
581
                {
582
                  setIsNetworkProperty(ps.component);
583
                  storeBannerAndRightComments(ps.component,@$);
584
                }
585
        ;
586
587
/*
588
 * Module Interface
589
 */
590
moduleinterfacedefinition
591
        : moduleinterfaceheader '{'
592
                {
593
                  ps.typescope.push(ps.component);
594
                  ps.blockscope.push(ps.component);
595
                  ps.parameters = (ParametersElement *)createElementWithTag(NED_PARAMETERS, ps.component);
596
                  ps.parameters->setIsImplicit(true);
597
                  ps.propertyscope.push(ps.parameters);
598
                }
599
            opt_paramblock
600
            opt_gateblock
601
          '}'
602
                {
603
                  ps.propertyscope.pop();
604
                  ps.blockscope.pop();
605
                  ps.component = ps.typescope.top();
606
                  ps.typescope.pop();
607
                  if (np->getStoreSourceFlag())
608
                      storeComponentSourceCode(ps.component, @$);
609
                  storePos(ps.component, @$);
610
                  storeTrailingComment(ps.component,@$);
611
                }
612
        ;
613
614
moduleinterfaceheader
615
        : MODULEINTERFACE NAME
616
                {
617
                  ps.component = (ModuleInterfaceElement *)createElementWithTag(NED_MODULE_INTERFACE, ps.inTypes ? (NEDElement *)ps.types : (NEDElement *)ps.nedfile);
618
                  ((ModuleInterfaceElement *)ps.component)->setName(toString(@2));
619
                }
620
           opt_interfaceinheritance
621
                { storeBannerAndRightComments(ps.component,@$); }
622
        ;
623
624
/*
625
 * Parameters
626
 */
627
opt_paramblock
628
        : opt_params   /* "parameters" keyword is optional */
629
                {
630
                  storePos(ps.parameters, @$);
631
                  if (!ps.parameters->getFirstChild()) { // delete "parameters" element if empty
632
                      ps.parameters->getParent()->removeChild(ps.parameters);
633
                      delete ps.parameters;
634
                  }
635
                }
636
        | PARAMETERS ':'
637
                {
638
                  ps.parameters->setIsImplicit(false);
639
                  storeBannerAndRightComments(ps.parameters,@1,@2);
640
                }
641
          opt_params
642
                { storePos(ps.parameters, @$); }
643
        ;
644
645
opt_params
646
        : params
647
        |
648
        ;
649
650
params
651
        : params paramsitem
652
        | paramsitem
653
        ;
654
655
paramsitem
656
        : param
657
        | property
658
        ;
659
660
param
661
        : param_typenamevalue
662
        | pattern_value
663
        ; /* no error recovery rule -- see discussion at top */
664
665
/*
666
 * Parameter
667
 */
668
param_typenamevalue
669
        : param_typename opt_inline_properties ';'
670
                {
671
                  ps.propertyscope.pop();
672
                  storePos(ps.param, @$);
673
                  storeBannerAndRightComments(ps.param,@$);
674
                }
675
        | param_typename opt_inline_properties '=' paramvalue opt_inline_properties ';'
676
                {
677
                  ps.propertyscope.pop();
678
                  if (!isEmpty(ps.exprPos))  // note: $4 cannot be checked, as it's always NULL when expression parsing is off
679
                      addExpression(ps.param, "value",ps.exprPos,$4);
680
                  else {
681
                      // Note: "=default" is currently not accepted in NED files, because
682
                      // it would be complicated to support in the Inifile Editor.
683
                      if (ps.isDefault)
684
                          np->getErrors()->addError(ps.param,"applying the default value (\"=default\" syntax) is not supported in NED files");
685
                  }
686
                  ps.param->setIsDefault(ps.isDefault);
687
                  storePos(ps.param, @$);
688
                  storeBannerAndRightComments(ps.param,@$);
689
                }
690
        ;
691
692
param_typename
693
        : opt_volatile paramtype NAME
694
                {
695
                  ps.param = addParameter(ps.parameters, @3);
696
                  ps.param->setType(ps.paramType);
697
                  ps.param->setIsVolatile(ps.isVolatile);
698
                  ps.propertyscope.push(ps.param);
699
                }
700
        | NAME
701
                {
702
                  ps.param = addParameter(ps.parameters, @1);
703
                  ps.propertyscope.push(ps.param);
704
                }
705
        ;
706
707
pattern_value
708
        : pattern '=' paramvalue ';'
709
                {
710
                  ps.param = addParameter(ps.parameters, @1);
711
                  ps.param->setIsPattern(true);
712
                  const char *patt = ps.param->getName();
713
                  if (strchr(patt,' ') || strchr(patt,'\t') || strchr(patt,'\n'))
714
                      np->getErrors()->addError(ps.param,"parameter name patterns may not contain whitespace");
715
                  if (!isEmpty(ps.exprPos))  // note: $3 cannot be checked, as it's always NULL when expression parsing is off
716
                      addExpression(ps.param, "value",ps.exprPos,$3);
717
                  else {
718
                      // Note: "=default" is currently not accepted in NED files, because
719
                      // it would be complicated to support in the Inifile Editor.
720
                      if (ps.isDefault)
721
                          np->getErrors()->addError(ps.param,"applying the default value (\"=default\" syntax) is not supported in NED files");
722
                  }
723
                  ps.param->setIsDefault(ps.isDefault);
724
                  storePos(ps.param, @$);
725
                  storeBannerAndRightComments(ps.param,@$);
726
                }
727
        ;
728
729
paramtype
730
        : DOUBLETYPE
731
                { ps.paramType = NED_PARTYPE_DOUBLE; }
732
        | INTTYPE
733
                { ps.paramType = NED_PARTYPE_INT; }
734
        | STRINGTYPE
735
                { ps.paramType = NED_PARTYPE_STRING; }
736
        | BOOLTYPE
737
                { ps.paramType = NED_PARTYPE_BOOL; }
738
        | XMLTYPE
739
                { ps.paramType = NED_PARTYPE_XML; }
740
        ;
741
742
opt_volatile
743
        : VOLATILE
744
                { ps.isVolatile = true; }
745
        |
746
                { ps.isVolatile = false; }
747
        ;
748
749
paramvalue
750
        : expression
751
                { $$ = $1; ps.exprPos = @1; ps.isDefault = false; }
752
        | DEFAULT '(' expression ')'
753
                { $$ = $3; ps.exprPos = @3; ps.isDefault = true; }
754
        | DEFAULT
755
                {
756
                  $$ = NULL; ps.exprPos = makeEmptyYYLTYPE(); ps.isDefault = true;
757
                }
758
        | ASK
759
                {
760
                  np->getErrors()->addError(ps.parameters,"interactive prompting (\"=ask\" syntax) is not supported in NED files");
761
                  $$ = NULL; ps.exprPos = makeEmptyYYLTYPE(); ps.isDefault = false;
762
                }
763
        ;
764
765
opt_inline_properties
766
        : inline_properties
767
        |
768
        ;
769
770
inline_properties
771
        : inline_properties property_namevalue
772
        | property_namevalue
773
        ;
774
775
pattern
776
        : pattern2 '.' pattern_elem  /* to ensure that pattern contains at least one '.' */
777
        ;
778
779
pattern2
780
        : pattern2 '.' pattern_elem
781
        | pattern_elem
782
        ;
783
784
pattern_elem
785
        : pattern_name
786
        | pattern_name '[' pattern_index ']'
787
        | pattern_name '[' '*' ']'
788
        | DOUBLEASTERISK
789
        ;
790
791
pattern_name
792
        : NAME
793
        | NAME '$' NAME  /* subgate */
794
        | CHANNEL    /* needed for setting channel parameters */
795
        | '{' pattern_index '}'
796
        | '*'
797
        | pattern_name NAME
798
        | pattern_name '{' pattern_index '}'
799
        | pattern_name '*'
800
        ;
801
802
pattern_index
803
        : INTCONSTANT
804
        | INTCONSTANT TO INTCONSTANT
805
        | TO INTCONSTANT
806
        | INTCONSTANT TO
807
        ;
808
809
/*
810
 * Property
811
 */
812
property
813
        : property_namevalue ';'
814
                {
815
                  storePos(ps.property, @$);
816
                  storeBannerAndRightComments(ps.property,@$);
817
                }
818
        ; /* no error recovery rule -- see discussion at top */
819
820
property_namevalue
821
        : property_name
822
        | property_name '(' opt_property_keys ')'
823
        ;
824
825
property_name
826
        : '@' NAME
827
                {
828
                  assertNonEmpty(ps.propertyscope);
829
                  ps.property = addProperty(ps.propertyscope.top(), toString(@2));
830
                  ps.propvals.clear(); // just to be safe
831
                }
832
        | '@' NAME '[' NAME ']'
833
                {
834
                  assertNonEmpty(ps.propertyscope);
835
                  ps.property = addProperty(ps.propertyscope.top(), toString(@2));
836
                  ps.property->setIndex(toString(@4));
837
                  ps.propvals.clear(); // just to be safe
838
                }
839
        ;
840
841
opt_property_keys
842
        : property_keys  /* can't allow epsilon rule here, because @foo() would result in "ambiguous syntax" :( */
843
        ;
844
845
property_keys
846
        : property_keys ';' property_key
847
        | property_key
848
        ;
849
850
property_key
851
        : NAME '=' property_values
852
                {
853
                  ps.propkey = (PropertyKeyElement *)createElementWithTag(NED_PROPERTY_KEY, ps.property);
854
                  ps.propkey->setName(toString(@1));
855
                  for (int i=0; i<(int)ps.propvals.size(); i++)
856
                      ps.propkey->appendChild(ps.propvals[i]);
857
                  ps.propvals.clear();
858
                  storePos(ps.propkey, @$);
859
                }
860
        | property_values
861
                {
862
                  ps.propkey = (PropertyKeyElement *)createElementWithTag(NED_PROPERTY_KEY, ps.property);
863
                  ps.propkey->appendChild($1);
864
                  for (int i=0; i<(int)ps.propvals.size(); i++)
865
                      ps.propkey->appendChild(ps.propvals[i]);
866
                  ps.propvals.clear();
867
                  storePos(ps.propkey, @$);
868
                }
869
        ;
870
871
property_values
872
        : property_values ',' property_value
873
                { ps.propvals.push_back($3); }
874
        | property_value
875
                { ps.propvals.push_back($1); }
876
        ;
877
878
property_value
879
        : property_value_tokens
880
                { $$ = createLiteral(NED_CONST_SPEC, @$, @$); }
881
        | STRINGCONSTANT
882
                { $$ = createStringLiteral(@1); }
883
        |  /*empty*/
884
                {
885
                  LiteralElement *node = (LiteralElement *)createElementWithTag(NED_LITERAL);
886
                  node->setType(NED_CONST_SPEC); // and leave both value and text at ""
887
                  $$ = node;
888
                }
889
        ;
890
891
property_value_tokens
892
        : property_value_tokens property_value_token
893
        | property_value_token
894
        ;
895
896
property_value_token
897
        : NAME | INTCONSTANT | REALCONSTANT | TRUE_ | FALSE_
898
        | '$' | '@' | ':' | '[' | ']' | '{' | '}' | '.' | '?'
899
        | '^' | '+' | '-' | '*' | '/' | '%' | '<' | '>' | EQ | NE | LE | GE   /*note: '=' not listed as it would cause ambiguity: "a=b" is key=value or a single value for the default key? */
900
        | DOUBLEASTERISK | TO | PLUSPLUS | OR | AND | XOR | NOT
901
        ;
902
903
/*
904
 * Gates
905
 */
906
opt_gateblock
907
        : gateblock
908
        |
909
        ;
910
911
gateblock
912
        : GATES ':'
913
                {
914
                  assertNonEmpty(ps.blockscope);
915
                  ps.gates = (GatesElement *)createElementWithTag(NED_GATES, ps.blockscope.top());
916
                  storeBannerAndRightComments(ps.gates,@1,@2);
917
                }
918
          opt_gates
919
                {
920
                  storePos(ps.gates, @$);
921
                }
922
        ;
923
924
opt_gates
925
        : gates
926
        |
927
        ;
928
929
gates
930
        : gates gate
931
                {
932
                  storeBannerAndRightComments(ps.gate,@2);
933
                }
934
        | gate
935
                {
936
                  storeBannerAndRightComments(ps.gate,@1);
937
                }
938
        ;
939
940
/*
941
 * Gate
942
 */
943
gate
944
        : gate_typenamesize
945
                {
946
                  ps.propertyscope.push(ps.gate);
947
                }
948
          opt_inline_properties ';'
949
                {
950
                  ps.propertyscope.pop();
951
                  storePos(ps.gate, @$);
952
                }
953
        ; /* no error recovery rule -- see discussion at top */
954
955
gate_typenamesize
956
        : gatetype NAME
957
                {
958
                  ps.gate = addGate(ps.gates, @2);
959
                  ps.gate->setType(ps.gateType);
960
                }
961
        | gatetype NAME '[' ']'
962
                {
963
                  ps.gate = addGate(ps.gates, @2);
964
                  ps.gate->setType(ps.gateType);
965
                  ps.gate->setIsVector(true);
966
                }
967
        | gatetype NAME vector
968
                {
969
                  ps.gate = addGate(ps.gates, @2);
970
                  ps.gate->setType(ps.gateType);
971
                  ps.gate->setIsVector(true);
972
                  addVector(ps.gate, "vector-size",@3,$3);
973
                }
974
        | NAME
975
                {
976
                  ps.gate = addGate(ps.gates, @1);
977
                }
978
        | NAME '[' ']'
979
                {
980
                  ps.gate = addGate(ps.gates, @1);
981
                  ps.gate->setIsVector(true);
982
                }
983
        | NAME vector
984
                {
985
                  ps.gate = addGate(ps.gates, @1);
986
                  ps.gate->setIsVector(true);
987
                  addVector(ps.gate, "vector-size",@2,$2);
988
                }
989
        ;
990
991
gatetype
992
        : INPUT_
993
                { ps.gateType = NED_GATETYPE_INPUT; }
994
        | OUTPUT_
995
                { ps.gateType = NED_GATETYPE_OUTPUT; }
996
        | INOUT_
997
                { ps.gateType = NED_GATETYPE_INOUT; }
998
        ;
999
1000
/*
1001
 * Local Types
1002
 */
1003
opt_typeblock
1004
        : typeblock
1005
        |
1006
        ;
1007
1008
typeblock
1009
        : TYPES ':'
1010
                {
1011
                  assertNonEmpty(ps.blockscope);
1012
                  ps.types = (TypesElement *)createElementWithTag(NED_TYPES, ps.blockscope.top());
1013
                  storeBannerAndRightComments(ps.types,@1,@2);
1014
                  if (ps.inTypes)
1015
                     np->getErrors()->addError(ps.types,"more than one level of type nesting is not allowed");
1016
                  ps.inTypes = true;
1017
                }
1018
           opt_localtypes
1019
                {
1020
                  ps.inTypes = false;
1021
                  storePos(ps.types, @$);
1022
                }
1023
        ;
1024
1025
opt_localtypes
1026
        : localtypes
1027
        |
1028
        ;
1029
1030
localtypes
1031
        : localtypes localtype
1032
        | localtype
1033
        ;
1034
1035
localtype
1036
        : propertydecl
1037
        | channeldefinition
1038
        | channelinterfacedefinition
1039
        | simplemoduledefinition
1040
        | compoundmoduledefinition
1041
        | networkdefinition
1042
        | moduleinterfacedefinition
1043
        | ';'
1044
        ;
1045
1046
/*
1047
 * Submodules
1048
 */
1049
opt_submodblock
1050
        : submodblock
1051
        |
1052
        ;
1053
1054
submodblock
1055
        : SUBMODULES ':'
1056
                {
1057
                  assertNonEmpty(ps.blockscope);
1058
                  ps.submods = (SubmodulesElement *)createElementWithTag(NED_SUBMODULES, ps.blockscope.top());
1059
                  storeBannerAndRightComments(ps.submods,@1,@2);
1060
                }
1061
          opt_submodules
1062
                {
1063
                  storePos(ps.submods, @$);
1064
                }
1065
        ;
1066
1067
opt_submodules
1068
        : submodules
1069
        |
1070
        ;
1071
1072
submodules
1073
        : submodules submodule
1074
        | submodule
1075
        ;
1076
1077
submodule
1078
        : submoduleheader ';'
1079
                {
1080
                  storeBannerAndRightComments(ps.submod,@1,@2);
1081
                  storePos(ps.submod, @$);
1082
                }
1083
        | submoduleheader '{'
1084
                {
1085
                  ps.blockscope.push(ps.submod);
1086
                  ps.parameters = (ParametersElement *)createElementWithTag(NED_PARAMETERS, ps.submod);
1087
                  ps.parameters->setIsImplicit(true);
1088
                  ps.propertyscope.push(ps.parameters);
1089
                  storeBannerAndRightComments(ps.submod,@1,@2);
1090
                }
1091
          opt_paramblock
1092
          opt_gateblock
1093
          '}' opt_semicolon
1094
                {
1095
                  ps.blockscope.pop();
1096
                  ps.propertyscope.pop();
1097
                  storePos(ps.submod, @$);
1098
                  storeTrailingComment(ps.submod,@$);
1099
                }
1100
        ; /* no error recovery rule -- see discussion at top */
1101
1102
submoduleheader
1103
        : submodulename ':' dottedname
1104
                {
1105
                  ps.submod->setType(removeSpaces(@3).c_str());
1106
                }
1107
        | submodulename ':' likeparam LIKE dottedname
1108
                {
1109
                  addLikeParam(ps.submod, "like-param", @3, $3);
1110
                  ps.submod->setLikeType(removeSpaces(@5).c_str());
1111
                }
1112
        ;
1113
1114
submodulename
1115
        : NAME
1116
                {
1117
                  ps.submod = (SubmoduleElement *)createElementWithTag(NED_SUBMODULE, ps.submods);
1118
                  ps.submod->setName(toString(@1));
1119
                }
1120
        |  NAME vector
1121
                {
1122
                  ps.submod = (SubmoduleElement *)createElementWithTag(NED_SUBMODULE, ps.submods);
1123
                  ps.submod->setName(toString(@1));
1124
                  addVector(ps.submod, "vector-size",@2,$2);
1125
                }
1126
        ;
1127
1128
likeparam
1129
        : '<' '>'
1130
                { $$ = NULL; }
1131
        | '<' expression '>' /* XXX this expression is the source of one shift-reduce conflict because it may contain '>' */
1132
                { $$ = $2; }
1133
        ;
1134
1135
/*
1136
 * Connections
1137
 */
1138
opt_connblock
1139
        : connblock
1140
        |
1141
        ;
1142
1143
connblock
1144
        : CONNECTIONS ALLOWUNCONNECTED ':'
1145
                {
1146
                  assertNonEmpty(ps.blockscope);
1147
                  ps.conns = (ConnectionsElement *)createElementWithTag(NED_CONNECTIONS, ps.blockscope.top());
1148
                  ps.conns->setAllowUnconnected(true);
1149
                  storeBannerAndRightComments(ps.conns,@1,@3);
1150
                }
1151
          opt_connections
1152
                {
1153
                  storePos(ps.conns, @$);
1154
                }
1155
        | CONNECTIONS ':'
1156
                {
1157
                  assertNonEmpty(ps.blockscope);
1158
                  ps.conns = (ConnectionsElement *)createElementWithTag(NED_CONNECTIONS, ps.blockscope.top());
1159
                  storeBannerAndRightComments(ps.conns,@1,@2);
1160
                }
1161
          opt_connections
1162
                {
1163
                  storePos(ps.conns, @$);
1164
                }
1165
        ;
1166
1167
opt_connections
1168
        : connections
1169
        |
1170
        ;
1171
1172
connections
1173
        : connections connectionsitem
1174
        | connectionsitem
1175
        ;
1176
1177
connectionsitem
1178
        : connectiongroup
1179
        | connection opt_loops_and_conditions ';'
1180
                {
1181
                  ps.chanspec = (ChannelSpecElement *)ps.conn->getFirstChildWithTag(NED_CHANNEL_SPEC);
1182
                  if (ps.chanspec)
1183
                      ps.conn->appendChild(ps.conn->removeChild(ps.chanspec)); // move channelspec to conform DTD
1184
                  if ($2) {
1185
                      transferChildren($2, ps.conn);
1186
                      delete $2;
1187
                  }
1188
                  storePos(ps.conn, @$);
1189
                  storeBannerAndRightComments(ps.conn,@$);
1190
                }
1191
        ; /* no error recovery rule -- see discussion at top */
1192
1193
connectiongroup
1194
        : opt_loops_and_conditions '{'
1195
                {
1196
                  if (ps.inConnGroup)
1197
                      np->getErrors()->addError(ps.conngroup,"nested connection groups are not allowed");
1198
                  ps.conngroup = (ConnectionGroupElement *)createElementWithTag(NED_CONNECTION_GROUP, ps.conns);
1199
                  if ($1) {
1200
                      // for's and if's were collected in a temporary UnknownElement, put them under conngroup now
1201
                      transferChildren($1, ps.conngroup);
1202
                      delete $1;
1203
                  }
1204
                  ps.inConnGroup = true;
1205
                  storeBannerAndRightComments(ps.conngroup,@1);
1206
                }
1207
          connections '}' opt_semicolon
1208
                {
1209
                  ps.inConnGroup = false;
1210
                  storePos(ps.conngroup,@$);
1211
                  storeTrailingComment(ps.conngroup,@$);
1212
                }
1213
        ;
1214
1215
opt_loops_and_conditions
1216
        : loops_and_conditions
1217
                { $$ = $1; }
1218
        |
1219
                { $$ = NULL; }
1220
        ;
1221
1222
loops_and_conditions
1223
        : loops_and_conditions ',' loop_or_condition
1224
                {
1225
                  $1->appendChild($3);
1226
                  $$ = $1;
1227
                }
1228
        | loop_or_condition
1229
                {
1230
                  $$ = new UnknownElement();
1231
                  $$->appendChild($1);
1232
                }
1233
        ;
1234
1235
loop_or_condition
1236
        : loop
1237
        | condition
1238
        ;
1239
1240
loop
1241
        : FOR NAME '=' expression TO expression
1242
                {
1243
                  ps.loop = (LoopElement *)createElementWithTag(NED_LOOP);
1244
                  ps.loop->setParamName( toString(@2) );
1245
                  addExpression(ps.loop, "from-value",@4,$4);
1246
                  addExpression(ps.loop, "to-value",@6,$6);
1247
                  storePos(ps.loop, @$);
1248
                  $$ = ps.loop;
1249
                }
1250
        ;
1251
1252
/*
1253
 * Connection
1254
 */
1255
connection
1256
        : leftgatespec RIGHTARROW rightgatespec
1257
                {
1258
                  ps.conn->setArrowDirection(NED_ARROWDIR_L2R);
1259
                }
1260
        | leftgatespec RIGHTARROW channelspec RIGHTARROW rightgatespec
1261
                {
1262
                  ps.conn->setArrowDirection(NED_ARROWDIR_L2R);
1263
                }
1264
        | leftgatespec LEFTARROW rightgatespec
1265
                {
1266
                  swapConnection(ps.conn);
1267
                  ps.conn->setArrowDirection(NED_ARROWDIR_R2L);
1268
                }
1269
        | leftgatespec LEFTARROW channelspec LEFTARROW rightgatespec
1270
                {
1271
                  swapConnection(ps.conn);
1272
                  ps.conn->setArrowDirection(NED_ARROWDIR_R2L);
1273
                }
1274
        | leftgatespec DBLARROW rightgatespec
1275
                {
1276
                  ps.conn->setArrowDirection(NED_ARROWDIR_BIDIR);
1277
                }
1278
        | leftgatespec DBLARROW channelspec DBLARROW rightgatespec
1279
                {
1280
                  ps.conn->setArrowDirection(NED_ARROWDIR_BIDIR);
1281
                }
1282
        ;
1283
1284
leftgatespec
1285
        : leftmod '.' leftgate
1286
        | parentleftgate
1287
        ;
1288
1289
leftmod
1290
        : NAME vector
1291
                {
1292
                  ps.conn = (ConnectionElement *)createElementWithTag(NED_CONNECTION, ps.inConnGroup ? (NEDElement*)ps.conngroup : (NEDElement*)ps.conns );
1293
                  ps.conn->setSrcModule( toString(@1) );
1294
                  addVector(ps.conn, "src-module-index",@2,$2);
1295
                }
1296
        | NAME
1297
                {
1298
                  ps.conn = (ConnectionElement *)createElementWithTag(NED_CONNECTION, ps.inConnGroup ? (NEDElement*)ps.conngroup : (NEDElement*)ps.conns );
1299
                  ps.conn->setSrcModule( toString(@1) );
1300
                }
1301
        ;
1302
1303
leftgate
1304
        : NAME opt_subgate
1305
                {
1306
                  ps.conn->setSrcGate( toString( @1) );
1307
                  ps.conn->setSrcGateSubg(ps.subgate);
1308
                }
1309
        | NAME opt_subgate vector
1310
                {
1311
                  ps.conn->setSrcGate( toString( @1) );
1312
                  ps.conn->setSrcGateSubg(ps.subgate);
1313
                  addVector(ps.conn, "src-gate-index",@3,$3);
1314
                }
1315
        | NAME opt_subgate PLUSPLUS
1316
                {
1317
                  ps.conn->setSrcGate( toString( @1) );
1318
                  ps.conn->setSrcGateSubg(ps.subgate);
1319
                  ps.conn->setSrcGatePlusplus(true);
1320
                }
1321
        ;
1322
1323
parentleftgate
1324
        : NAME opt_subgate
1325
                {
1326
                  ps.conn = (ConnectionElement *)createElementWithTag(NED_CONNECTION, ps.inConnGroup ? (NEDElement*)ps.conngroup : (NEDElement*)ps.conns );
1327
                  ps.conn->setSrcModule("");
1328
                  ps.conn->setSrcGate(toString(@1));
1329
                  ps.conn->setSrcGateSubg(ps.subgate);
1330
                }
1331
        | NAME opt_subgate vector
1332
                {
1333
                  ps.conn = (ConnectionElement *)createElementWithTag(NED_CONNECTION, ps.inConnGroup ? (NEDElement*)ps.conngroup : (NEDElement*)ps.conns );
1334
                  ps.conn->setSrcModule("");
1335
                  ps.conn->setSrcGate(toString(@1));
1336
                  ps.conn->setSrcGateSubg(ps.subgate);
1337
                  addVector(ps.conn, "src-gate-index",@3,$3);
1338
                }
1339
        | NAME opt_subgate PLUSPLUS
1340
                {
1341
                  ps.conn = (ConnectionElement *)createElementWithTag(NED_CONNECTION, ps.inConnGroup ? (NEDElement*)ps.conngroup : (NEDElement*)ps.conns );
1342
                  ps.conn->setSrcModule("");
1343
                  ps.conn->setSrcGate(toString(@1));
1344
                  ps.conn->setSrcGateSubg(ps.subgate);
1345
                  ps.conn->setSrcGatePlusplus(true);
1346
                }
1347
        ;
1348
1349
rightgatespec
1350
        : rightmod '.' rightgate
1351
        | parentrightgate
1352
        ;
1353
1354
rightmod
1355
        : NAME
1356
                {
1357
                  ps.conn->setDestModule( toString(@1) );
1358
                }
1359
        | NAME vector
1360
                {
1361
                  ps.conn->setDestModule( toString(@1) );
1362
                  addVector(ps.conn, "dest-module-index",@2,$2);
1363
                }
1364
        ;
1365
1366
rightgate
1367
        : NAME opt_subgate
1368
                {
1369
                  ps.conn->setDestGate( toString( @1) );
1370
                  ps.conn->setDestGateSubg(ps.subgate);
1371
                }
1372
        | NAME opt_subgate vector
1373
                {
1374
                  ps.conn->setDestGate( toString( @1) );
1375
                  ps.conn->setDestGateSubg(ps.subgate);
1376
                  addVector(ps.conn, "dest-gate-index",@3,$3);
1377
                }
1378
        | NAME opt_subgate PLUSPLUS
1379
                {
1380
                  ps.conn->setDestGate( toString( @1) );
1381
                  ps.conn->setDestGateSubg(ps.subgate);
1382
                  ps.conn->setDestGatePlusplus(true);
1383
                }
1384
        ;
1385
1386
parentrightgate
1387
        : NAME opt_subgate
1388
                {
1389
                  ps.conn->setDestGate( toString( @1) );
1390
                  ps.conn->setDestGateSubg(ps.subgate);
1391
                }
1392
        | NAME opt_subgate vector
1393
                {
1394
                  ps.conn->setDestGate( toString( @1) );
1395
                  ps.conn->setDestGateSubg(ps.subgate);
1396
                  addVector(ps.conn, "dest-gate-index",@3,$3);
1397
                }
1398
        | NAME opt_subgate PLUSPLUS
1399
                {
1400
                  ps.conn->setDestGate( toString( @1) );
1401
                  ps.conn->setDestGateSubg(ps.subgate);
1402
                  ps.conn->setDestGatePlusplus(true);
1403
                }
1404
        ;
1405
1406
opt_subgate
1407
        : '$' NAME
1408
                {
1409
                  const char *s = toString(@2);
1410
                  if (!strcmp(s,"i"))
1411
                      ps.subgate = NED_SUBGATE_I;
1412
                  else if (!strcmp(s,"o"))
1413
                      ps.subgate = NED_SUBGATE_O;
1414
                  else
1415
                       np->getErrors()->addError(currentLocation(), "invalid subgate spec `%s', must be `i' or `o'", toString(@2));
1416
                }
1417
        |
1418
                { ps.subgate = NED_SUBGATE_NONE; }
1419
        ;
1420
1421
channelspec
1422
        : channelspec_header
1423
                { storePos(ps.chanspec, @$); }
1424
        | channelspec_header '{'
1425
                {
1426
                  ps.parameters = (ParametersElement *)createElementWithTag(NED_PARAMETERS, ps.chanspec);
1427
                  ps.parameters->setIsImplicit(true);
1428
                  ps.propertyscope.push(ps.parameters);
1429
                }
1430
            opt_paramblock
1431
          '}'
1432
                {
1433
                  ps.propertyscope.pop();
1434
                  storePos(ps.chanspec, @$);
1435
                }
1436
        ;
1437
1438
1439
channelspec_header
1440
        :
1441
                {
1442
                  ps.chanspec = (ChannelSpecElement *)createElementWithTag(NED_CHANNEL_SPEC, ps.conn);
1443
                }
1444
        | dottedname
1445
                {
1446
                  ps.chanspec = (ChannelSpecElement *)createElementWithTag(NED_CHANNEL_SPEC, ps.conn);
1447
                  ps.chanspec->setType(removeSpaces(@1).c_str());
1448
                }
1449
        | likeparam LIKE dottedname
1450
                {
1451
                  ps.chanspec = (ChannelSpecElement *)createElementWithTag(NED_CHANNEL_SPEC, ps.conn);
1452
                  addLikeParam(ps.chanspec, "like-param", @1, $1);
1453
                  ps.chanspec->setLikeType(removeSpaces(@3).c_str());
1454
                }
1455
        ;
1456
1457
/*
1458
 * Condition
1459
 */
1460
condition
1461
        : IF expression
1462
                {
1463
                  ps.condition = (ConditionElement *)createElementWithTag(NED_CONDITION);
1464
                  addExpression(ps.condition, "condition",@2,$2);
1465
                  storePos(ps.condition, @$);
1466
                  $$ = ps.condition;
1467
                }
1468
        ;
1469
1470
/*
1471
 * Common part
1472
 */
1473
vector
1474
        : '[' expression ']'
1475
                { $$ = $2; }
1476
        ;
1477
1478
expression
1479
        :
1480
          expr
1481
                {
1482
                  if (np->getParseExpressionsFlag()) $$ = createExpression($1);
1483
                }
1484
        | xmldocvalue
1485
                {
1486
                  if (np->getParseExpressionsFlag()) $$ = createExpression($1);
1487
                }
1488
        ;
1489
1490
/*
1491
 * Expressions
1492
 */
1493
/* FIXME TBD: storePos() stuff for expressions */
1494
xmldocvalue
1495
        : XMLDOC '(' stringliteral ',' stringliteral ')'
1496
                { if (np->getParseExpressionsFlag()) $$ = createFunction("xmldoc", $3, $5); }
1497
        | XMLDOC '(' stringliteral ')'
1498
                { if (np->getParseExpressionsFlag()) $$ = createFunction("xmldoc", $3); }
1499
        ;
1500
1501
expr
1502
        : simple_expr
1503
        | '(' expr ')'
1504
                { $$ = $2; }
1505
        | CONST_ '(' expr ')'
1506
                { if (np->getParseExpressionsFlag()) $$ = createFunction("const", $3); }
1507
1508
        | expr '+' expr
1509
                { if (np->getParseExpressionsFlag()) $$ = createOperator("+", $1, $3); }
1510
        | expr '-' expr
1511
                { if (np->getParseExpressionsFlag()) $$ = createOperator("-", $1, $3); }
1512
        | expr '*' expr
1513
                { if (np->getParseExpressionsFlag()) $$ = createOperator("*", $1, $3); }
1514
        | expr '/' expr
1515
                { if (np->getParseExpressionsFlag()) $$ = createOperator("/", $1, $3); }
1516
        | expr '%' expr
1517
                { if (np->getParseExpressionsFlag()) $$ = createOperator("%", $1, $3); }
1518
        | expr '^' expr
1519
                { if (np->getParseExpressionsFlag()) $$ = createOperator("^", $1, $3); }
1520
1521
        | '-' expr
1522
                %prec UMIN
1523
                { if (np->getParseExpressionsFlag()) $$ = unaryMinus($2); }
1524
1525
        | expr EQ expr
1526
                { if (np->getParseExpressionsFlag()) $$ = createOperator("==", $1, $3); }
1527
        | expr NE expr
1528
                { if (np->getParseExpressionsFlag()) $$ = createOperator("!=", $1, $3); }
1529
        | expr '>' expr
1530
                { if (np->getParseExpressionsFlag()) $$ = createOperator(">", $1, $3); }
1531
        | expr GE expr
1532
                { if (np->getParseExpressionsFlag()) $$ = createOperator(">=", $1, $3); }
1533
        | expr '<' expr
1534
                { if (np->getParseExpressionsFlag()) $$ = createOperator("<", $1, $3); }
1535
        | expr LE expr
1536
                { if (np->getParseExpressionsFlag()) $$ = createOperator("<=", $1, $3); }
1537
1538
        | expr AND expr
1539
                { if (np->getParseExpressionsFlag()) $$ = createOperator("&&", $1, $3); }
1540
        | expr OR expr
1541
                { if (np->getParseExpressionsFlag()) $$ = createOperator("||", $1, $3); }
1542
        | expr XOR expr
1543
                { if (np->getParseExpressionsFlag()) $$ = createOperator("##", $1, $3); }
1544
1545
        | NOT expr
1546
                %prec UMIN
1547
                { if (np->getParseExpressionsFlag()) $$ = createOperator("!", $2); }
1548
1549
        | expr BIN_AND expr
1550
                { if (np->getParseExpressionsFlag()) $$ = createOperator("&", $1, $3); }
1551
        | expr BIN_OR expr
1552
                { if (np->getParseExpressionsFlag()) $$ = createOperator("|", $1, $3); }
1553
        | expr BIN_XOR expr
1554
                { if (np->getParseExpressionsFlag()) $$ = createOperator("#", $1, $3); }
1555
1556
        | BIN_COMPL expr
1557
                %prec UMIN
1558
                { if (np->getParseExpressionsFlag()) $$ = createOperator("~", $2); }
1559
        | expr SHIFT_LEFT expr
1560
                { if (np->getParseExpressionsFlag()) $$ = createOperator("<<", $1, $3); }
1561
        | expr SHIFT_RIGHT expr
1562
                { if (np->getParseExpressionsFlag()) $$ = createOperator(">>", $1, $3); }
1563
        | expr '?' expr ':' expr
1564
                { if (np->getParseExpressionsFlag()) $$ = createOperator("?:", $1, $3, $5); }
1565
1566
        | INTTYPE '(' expr ')'
1567
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3); }
1568
        | DOUBLETYPE '(' expr ')'
1569
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3); }
1570
        | STRINGTYPE '(' expr ')'
1571
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3); }
1572
1573
        | NAME '(' ')'
1574
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1)); }
1575
        | NAME '(' expr ')'
1576
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3); }
1577
        | NAME '(' expr ',' expr ')'
1578
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5); }
1579
        | NAME '(' expr ',' expr ',' expr ')'
1580
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7); }
1581
        | NAME '(' expr ',' expr ',' expr ',' expr ')'
1582
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7, $9); }
1583
        | NAME '(' expr ',' expr ',' expr ',' expr ',' expr ')'
1584
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7, $9, $11); }
1585
        | NAME '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
1586
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7, $9, $11, $13); }
1587
        | NAME '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
1588
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7, $9, $11, $13, $15); }
1589
        | NAME '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
1590
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7, $9, $11, $13, $15, $17); }
1591
        | NAME '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
1592
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7, $9, $11, $13, $15, $17, $19); }
1593
        | NAME '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
1594
                { if (np->getParseExpressionsFlag()) $$ = createFunction(toString(@1), $3, $5, $7, $9, $11, $13, $15, $17, $19, $21); }
1595
1596
        ;
1597
1598
simple_expr
1599
        : identifier
1600
        | special_expr
1601
        | literal
1602
        ;
1603
1604
identifier
1605
        : NAME
1606
                { if (np->getParseExpressionsFlag()) $$ = createIdent(@1); }
1607
        | THIS_ '.' NAME
1608
                { if (np->getParseExpressionsFlag()) $$ = createIdent(@3, @1); }
1609
        | NAME '.' NAME
1610
                { if (np->getParseExpressionsFlag()) $$ = createIdent(@3, @1); }
1611
        | NAME '[' expr ']' '.' NAME
1612
                { if (np->getParseExpressionsFlag()) $$ = createIdent(@6, @1, $3); }
1613
        ;
1614
1615
special_expr
1616
        : INDEX_
1617
                { if (np->getParseExpressionsFlag()) $$ = createFunction("index"); }
1618
        | INDEX_ '(' ')'
1619
                { if (np->getParseExpressionsFlag()) $$ = createFunction("index"); }
1620
        | SIZEOF '(' identifier ')'
1621
                { if (np->getParseExpressionsFlag()) $$ = createFunction("sizeof", $3); }
1622
        ;
1623
1624
literal
1625
        : stringliteral
1626
        | boolliteral
1627
        | numliteral
1628
        ;
1629
1630
stringliteral
1631
        : STRINGCONSTANT
1632
                { if (np->getParseExpressionsFlag()) $$ = createStringLiteral(@1); }
1633
        ;
1634
1635
boolliteral
1636
        : TRUE_
1637
                { if (np->getParseExpressionsFlag()) $$ = createLiteral(NED_CONST_BOOL, @1, @1); }
1638
        | FALSE_
1639
                { if (np->getParseExpressionsFlag()) $$ = createLiteral(NED_CONST_BOOL, @1, @1); }
1640
        ;
1641
1642
numliteral
1643
        : INTCONSTANT
1644
                { if (np->getParseExpressionsFlag()) $$ = createLiteral(NED_CONST_INT, @1, @1); }
1645
        | REALCONSTANT
1646
                { if (np->getParseExpressionsFlag()) $$ = createLiteral(NED_CONST_DOUBLE, @1, @1); }
1647
        | quantity
1648
                { if (np->getParseExpressionsFlag()) $$ = createQuantityLiteral(@1); }
1649
        ;
1650
1651
quantity
1652
        : quantity INTCONSTANT NAME
1653
        | quantity REALCONSTANT NAME
1654
        | INTCONSTANT NAME
1655
        | REALCONSTANT NAME
1656
        ;
1657
1658
opt_semicolon
1659
        : ';'
1660
        |
1661
        ;
1662
1663
%%
1664
1665
//----------------------------------------------------------------------
1666
// general bison/flex stuff:
1667
//
1668
1669
NEDElement *doParseNED2(NEDParser *p, const char *nedtext)
1670
{
1671
#if YYDEBUG != 0      /* #if added --VA */
1672
    yydebug = YYDEBUGGING_ON;
1673
#endif
1674
1675
    NONREENTRANT_NED_PARSER(p);
1676
1677
    // reset the lexer
1678
    pos.co = 0;
1679
    pos.li = 1;
1680
    prevpos = pos;
1681
1682
    yyin = NULL;
1683
    yyout = stderr; // not used anyway
1684
1685
    // alloc buffer
1686
    struct yy_buffer_state *handle = yy_scan_string(nedtext);
1687
    if (!handle)
1688
        {np->getErrors()->addError("", "unable to allocate work memory"); return false;}
1689
1690
    // create parser state and NEDFileElement
1691
    resetParserState();
1692
    ps.nedfile = new NedFileElement();
1693
1694
    // store file name with slashes always, even on Windows -- neddoc relies on that
1695
    ps.nedfile->setFilename(slashifyFilename(np->getFileName()).c_str());
1696
    ps.nedfile->setVersion("2");
1697
1698
    // store file comment
1699
    storeFileComment(ps.nedfile);
1700
1701
    ps.propertyscope.push(ps.nedfile);
1702
1703
    globalps = ps; // remember this for error recovery
1704
1705
    if (np->getStoreSourceFlag())
1706
        storeSourceCode(ps.nedfile, np->getSource()->getFullTextPos());
1707
1708
    // parse
1709
    int ret;
1710
    try
1711
    {
1712
        ret = yyparse();
1713
    }
1714
    catch (NEDException& e)
1715
    {
1716
        yyerror((std::string("error during parsing: ")+e.what()).c_str());
1717
        yy_delete_buffer(handle);
1718
        return 0;
1719
    }
1720
1721
    if (np->getErrors()->empty())
1722
    {
1723
        // more sanity checks
1724
        if (ps.propertyscope.size()!=1 || ps.propertyscope.top()!=ps.nedfile)
1725
            INTERNAL_ERROR0(NULL, "error during parsing: imbalanced propertyscope");
1726
        if (!ps.blockscope.empty() || !ps.typescope.empty())
1727
            INTERNAL_ERROR0(NULL, "error during parsing: imbalanced blockscope or typescope");
1728
    }
1729
    yy_delete_buffer(handle);
1730
1731
    //FIXME TODO: fill in @documentation properties from comments
1732
    return ps.nedfile;
1733
}
1734
1735
void yyerror(const char *s)
1736
{
1737
    // chop newline
1738
    char buf[250];
1739
    strcpy(buf, s);
1740
    if (buf[strlen(buf)-1] == '\n')
1741
        buf[strlen(buf)-1] = '\0';
1742
1743
    np->error(buf, pos.li);
1744
}