Project

General

Profile

Statistics
| Branch: | Revision:

root / src / nedxml / ned2generator.cc @ 79bb12dc

History | View | Annotate | Download (41.5 KB)

1
//==========================================================================
2
//  NEDGENERATOR.CC - part of
3
//
4
//                     OMNeT++/OMNEST
5
//            Discrete System Simulation in C++
6
//
7
//==========================================================================
8

    
9
/*--------------------------------------------------------------*
10
  Copyright (C) 2002-2008 Andras Varga
11
  Copyright (C) 2006-2008 OpenSim Ltd.
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

    
18
#include <string.h>
19
#include <string>
20
#include <sstream>
21
#include "ned2generator.h"
22
#include "nedutil.h"
23
#include "stringutil.h"
24
#include "nederror.h"
25

    
26
NAMESPACE_BEGIN
27

    
28
using std::ostream;
29

    
30
#define DEFAULTINDENT "            "
31

    
32
void generateNED2(ostream& out, NEDElement *node, NEDErrorStore *e)
33
{
34
    NED2Generator nedgen(e);
35
    nedgen.generate(out, node, "");
36
}
37

    
38
//-----------------------------------------
39

    
40
#define OUT  (*outp)
41

    
42
NED2Generator::NED2Generator(NEDErrorStore *e)
43
{
44
    outp = NULL;
45
    indentsize = 4;
46
    errors = e;
47
}
48

    
49
NED2Generator::~NED2Generator()
50
{
51
}
52

    
53
void NED2Generator::setIndentSize(int indentsiz)
54
{
55
    indentsize = indentsiz;
56
}
57

    
58
void NED2Generator::generate(ostream& out, NEDElement *node, const char *indent)
59
{
60
    outp = &out;
61
    generateNedItem(node, indent, false);
62
    outp = NULL;
63
}
64

    
65
std::string NED2Generator::generate(NEDElement *node, const char *indent)
66
{
67
    std::stringstream ss;
68
    generate(ss, node, indent);
69
    return ss.str();
70
}
71

    
72
const char *NED2Generator::increaseIndent(const char *indent)
73
{
74
    // biggest possible indent: ~70 chars:
75
    static char spaces[] = "                                                                     ";
76

    
77
    // bump...
78
    int ilen = strlen(indent);
79
    if (ilen+indentsize <= (int)sizeof(spaces)-1)
80
        ilen+=indentsize;
81
    const char *newindent = spaces+sizeof(spaces)-1-ilen;
82
    return newindent;
83
}
84

    
85
const char *NED2Generator::decreaseIndent(const char *indent)
86
{
87
    return indent + indentsize;
88
}
89

    
90
//---------------------------------------------------------------------------
91

    
92
static bool _isNetwork(NEDElement *node)
93
{
94
    Assert(node->getTagCode()==NED_COMPOUND_MODULE || node->getTagCode()==NED_SIMPLE_MODULE);
95
    return NEDElementUtil::getLocalBoolProperty(node, "isNetwork");
96
}
97

    
98
//---------------------------------------------------------------------------
99

    
100
void NED2Generator::generateChildren(NEDElement *node, const char *indent, const char *arg)
101
{
102
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
103
        generateNedItem(child, indent, child==node->getLastChild(), arg);
104
}
105

    
106
void NED2Generator::generateChildrenWithType(NEDElement *node, int tagcode, const char *indent, const char *arg)
107
{
108
    // find last
109
    NEDElement *lastWithTag = NULL;
110
    for (NEDElement *child1=node->getFirstChild(); child1; child1=child1->getNextSibling())
111
        if (child1->getTagCode()==tagcode)
112
             lastWithTag = child1;
113

    
114
    // now the recursive call
115
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
116
        if (child->getTagCode()==tagcode)
117
            generateNedItem(child, indent, child==lastWithTag, arg);
118
}
119

    
120
static int isInVector(int a, int v[])
121
{
122
    for (int i=0; v[i]; i++)  // v[] is zero-terminated
123
        if (v[i]==a)
124
            return true;
125
    return false;
126
}
127

    
128
void NED2Generator::generateChildrenWithTypes(NEDElement *node, int tagcodes[], const char *indent, const char *arg)
129
{
130
    // find last
131
    NEDElement *lastWithTag = NULL;
132
    for (NEDElement *child1=node->getFirstChild(); child1; child1=child1->getNextSibling())
133
        if (isInVector(child1->getTagCode(), tagcodes))
134
             lastWithTag = child1;
135

    
136
    // now the recursive call
137
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
138
        if (isInVector(child->getTagCode(), tagcodes))
139
            generateNedItem(child, indent, child==lastWithTag, arg);
140
}
141

    
142
//---------------------------------------------------------------------------
143

    
144
void NED2Generator::printInheritance(NEDElement *node, const char *indent)
145
{
146
    if (node->getFirstChildWithTag(NED_EXTENDS))
147
    {
148
        OUT << " extends ";
149
        generateChildrenWithType(node, NED_EXTENDS, increaseIndent(indent), ", ");
150
    }
151

    
152
    if (node->getFirstChildWithTag(NED_INTERFACE_NAME))
153
    {
154
        OUT << " like ";
155
        generateChildrenWithType(node, NED_INTERFACE_NAME, increaseIndent(indent), ", ");
156
    }
157
}
158

    
159
bool NED2Generator::hasExpression(NEDElement *node, const char *attr)
160
{
161
    if (!opp_isempty(node->getAttribute(attr)))
162
    {
163
        return true;
164
    }
165
    else
166
    {
167
        for (ExpressionElement *expr=(ExpressionElement *)node->getFirstChildWithTag(NED_EXPRESSION); expr; expr=expr->getNextExpressionSibling())
168
            if (!opp_isempty(expr->getTarget()) && !strcmp(expr->getTarget(),attr))
169
                return true;
170
        return false;
171
    }
172
}
173

    
174
void NED2Generator::printExpression(NEDElement *node, const char *attr, const char *indent)
175
{
176
    if (!opp_isempty(node->getAttribute(attr)))
177
    {
178
        OUT << node->getAttribute(attr);
179
    }
180
    else
181
    {
182
        for (ExpressionElement *expr=(ExpressionElement *)node->getFirstChildWithTag(NED_EXPRESSION); expr; expr=expr->getNextExpressionSibling())
183
            if (!opp_isempty(expr->getTarget()) && !strcmp(expr->getTarget(),attr))
184
                generateNedItem(expr, indent, false, NULL);
185
    }
186
}
187

    
188
void NED2Generator::printOptVector(NEDElement *node, const char *attr, const char *indent)
189
{
190
    if (hasExpression(node,attr))
191
    {
192
        OUT << "[";
193
        printExpression(node,attr,indent);
194
        OUT << "]";
195
    }
196
}
197

    
198
//---------------------------------------------------------------------------
199

    
200
static const char *getComment(NEDElement *node, const char *locId)
201
{
202
    CommentElement *comment = (CommentElement *)node->getFirstChildWithAttribute(NED_COMMENT, "locid", locId);
203
    return (comment && !opp_isempty(comment->getContent())) ? comment->getContent() : NULL;
204
}
205

    
206
static std::string formatComment(const char *comment, const char *indent, const char *defaultValue)
207
{
208
    if (!comment || !comment[0])
209
        return defaultValue;
210

    
211
    // indent each line of comment; also ensure that if last line contains
212
    // a comment (//), it gets terminated by newline. If indent==NULL,
213
    // keep original indent
214
    std::string ret;
215
    const char *curLine = comment;
216
    while (curLine[0])
217
    {
218
        const char *nextLine = strchr(curLine,'\n');
219
        if (!nextLine)
220
            nextLine = curLine + strlen(curLine);
221
        const char *commentStart = strstr(curLine, "//");
222
        if (!commentStart || commentStart>=nextLine)
223
            ret += "\n"; // no comment in that line -- just add newline
224
        else if (!indent)
225
            ret += std::string(curLine, nextLine) + "\n"; // use original indent
226
        else
227
            ret += indent + std::string(commentStart, nextLine) + "\n"; // indent the comment
228

    
229
        curLine = nextLine[0] ? nextLine+1 : nextLine; // +1: skip newline
230
    }
231
    return ret;
232
}
233

    
234
std::string NED2Generator::concatInnerComments(NEDElement *node)
235
{
236
    std::string ret;
237
    for (NEDElement *child=node->getFirstChildWithTag(NED_COMMENT); child; child = child->getNextSiblingWithTag(NED_COMMENT))
238
    {
239
        CommentElement *comment = (CommentElement *)child;
240
        if (!strcmp(comment->getLocid(), "inner"))
241
            ret += comment->getContent();
242
    }
243
    return ret;
244
}
245

    
246
std::string NED2Generator::getBannerComment(NEDElement *node, const char *indent)
247
{
248
    const char *comment = getComment(node, "banner");
249
    std::string innerComments = concatInnerComments(node);
250
    return formatComment(comment, indent, "") + formatComment(innerComments.c_str(), indent, "");
251
}
252

    
253
std::string NED2Generator::getRightComment(NEDElement *node)
254
{
255
    const char *comment = getComment(node, "right");
256
    return formatComment(comment, NULL, "\n");
257
}
258

    
259
std::string NED2Generator::getInlineRightComment(NEDElement *node)
260
{
261
    const char *comment = getComment(node, "right");
262
    return formatComment(comment, NULL, " ");
263
}
264

    
265
std::string NED2Generator::getTrailingComment(NEDElement *node)
266
{
267
    const char *comment = getComment(node, "trailing");
268
    return formatComment(comment, NULL, "\n");
269
}
270

    
271
//---------------------------------------------------------------------------
272

    
273
void NED2Generator::doFiles(FilesElement *node, const char *indent, bool, const char *)
274
{
275
    generateChildren(node, indent);
276
}
277

    
278
void NED2Generator::doNedFile(NedFileElement *node, const char *indent, bool, const char *)
279
{
280
    OUT << getBannerComment(node, indent);
281
    generateChildren(node, indent);
282
}
283

    
284
void NED2Generator::doPackage(PackageElement *node, const char *indent, bool islast, const char *)
285
{
286
    OUT << getBannerComment(node, indent);
287
    OUT << indent << "package " << node->getName() << ";" << getRightComment(node);
288
}
289

    
290
void NED2Generator::doImport(ImportElement *node, const char *indent, bool islast, const char *)
291
{
292
    OUT << getBannerComment(node, indent);
293
    OUT << indent << "import " << node->getImportSpec() << ";" << getRightComment(node);
294
}
295

    
296
void NED2Generator::doPropertyDecl(PropertyDeclElement *node, const char *indent, bool islast, const char *)
297
{
298
    OUT << getBannerComment(node, indent);
299
    OUT << indent << "property @" << node->getName();
300
    if (node->getIsArray())
301
        OUT << "[]";
302
    if (node->getFirstChildWithTag(NED_PROPERTY_KEY))
303
    {
304
        OUT << "(";
305
        generateChildrenWithType(node, NED_PROPERTY_KEY, increaseIndent(indent), "; ");
306
        OUT << ")";
307
    }
308
    OUT << ";" << getRightComment(node);
309
}
310

    
311
void NED2Generator::doExtends(ExtendsElement *node, const char *indent, bool islast, const char *sep)
312
{
313
    OUT << node->getName();
314
    if (!islast && sep)
315
        OUT << (sep ? sep : "");
316
}
317

    
318
void NED2Generator::doInterfaceName(InterfaceNameElement *node, const char *indent, bool islast, const char *sep)
319
{
320
    OUT << node->getName();
321
    if (!islast && sep)
322
        OUT << (sep ? sep : "");
323
}
324

    
325
void NED2Generator::doSimpleModule(SimpleModuleElement *node, const char *indent, bool islast, const char *)
326
{
327
    OUT << getBannerComment(node, indent);
328
    OUT << indent << "simple " << node->getName();
329
    printInheritance(node, indent);
330
    OUT << getRightComment(node);
331
    OUT << indent << "{\n";
332

    
333
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
334
    generateChildrenWithType(node, NED_GATES, increaseIndent(indent));
335

    
336
    OUT << indent << "}" << getTrailingComment(node);
337
}
338

    
339
void NED2Generator::doModuleInterface(ModuleInterfaceElement *node, const char *indent, bool islast, const char *)
340
{
341
    OUT << getBannerComment(node, indent);
342
    OUT << indent << "moduleinterface " << node->getName();
343
    printInheritance(node, indent);
344
    OUT << getRightComment(node);
345
    OUT << indent << "{\n";
346

    
347
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
348
    generateChildrenWithType(node, NED_GATES, increaseIndent(indent));
349

    
350
    OUT << indent << "}" << getTrailingComment(node);
351
}
352

    
353
void NED2Generator::doCompoundModule(CompoundModuleElement *node, const char *indent, bool islast, const char *)
354
{
355
    OUT << getBannerComment(node, indent);
356
    OUT << indent << (_isNetwork(node) ? "network" : "module") << " " << node->getName();
357
    printInheritance(node, indent);
358
    OUT << getRightComment(node);
359
    OUT << indent << "{\n";
360

    
361
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
362
    generateChildrenWithType(node, NED_GATES, increaseIndent(indent));
363
    generateChildrenWithType(node, NED_TYPES, increaseIndent(indent));
364
    generateChildrenWithType(node, NED_SUBMODULES, increaseIndent(indent));
365
    generateChildrenWithType(node, NED_CONNECTIONS, increaseIndent(indent));
366

    
367
    OUT << indent << "}" << getTrailingComment(node);
368
}
369

    
370
void NED2Generator::doChannelInterface(ChannelInterfaceElement *node, const char *indent, bool islast, const char *)
371
{
372
    OUT << getBannerComment(node, indent);
373
    OUT << indent << "channelinterface " << node->getName();
374
    printInheritance(node, indent);
375
    OUT << getRightComment(node);
376
    OUT << indent << "{\n";
377

    
378
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
379

    
380
    OUT << indent << "}" << getTrailingComment(node);
381
}
382

    
383
void NED2Generator::doChannel(ChannelElement *node, const char *indent, bool islast, const char *)
384
{
385
    OUT << getBannerComment(node, indent);
386
    OUT << indent << "channel ";
387
    OUT << node->getName();
388
    printInheritance(node, indent);
389
    OUT << getRightComment(node);
390
    OUT << indent << "{\n";
391

    
392
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
393

    
394
    OUT << indent << "}" << getTrailingComment(node);
395
}
396

    
397
void NED2Generator::doParameters(ParametersElement *node, const char *indent, bool islast, const char *)
398
{
399
    OUT << getBannerComment(node, indent);
400
    if (!node->getIsImplicit())
401
        OUT << indent << "parameters:" << getRightComment(node);
402

    
403
    // inside channel-spec, everything has to be on one line except it'd be too long
404
    // (rule of thumb: if it contains a param group or "parameters:" keyword is explicit)
405
    bool inlineParams = node->getIsImplicit() && node->getParent() && node->getParent()->getTagCode()==NED_CHANNEL_SPEC;
406
    generateChildren(node, inlineParams ? NULL : node->getIsImplicit() ? indent : increaseIndent(indent));
407
}
408

    
409
void NED2Generator::doParam(ParamElement *node, const char *indent, bool islast, const char *)
410
{
411
    OUT << getBannerComment(node, indent);
412
    if (indent)
413
        OUT << indent;
414
    else
415
        OUT << " ";  // inline params, used for channel-spec in connections
416

    
417
    if (node->getIsVolatile())
418
        OUT << "volatile ";
419
    switch (node->getType())
420
    {
421
        case NED_PARTYPE_NONE:   break;
422
        case NED_PARTYPE_DOUBLE: OUT << "double "; break;
423
        case NED_PARTYPE_INT:    OUT << "int "; break;
424
        case NED_PARTYPE_STRING: OUT << "string "; break;
425
        case NED_PARTYPE_BOOL:   OUT << "bool "; break;
426
        case NED_PARTYPE_XML:    OUT << "xml "; break;
427
        default: INTERNAL_ERROR0(node, "wrong type");
428
    }
429
    OUT << node->getName();
430

    
431
    const char *subindent = indent ? increaseIndent(indent) : DEFAULTINDENT;
432
    generateChildrenWithType(node, NED_PROPERTY, subindent, " ");
433

    
434
    if (hasExpression(node,"value"))
435
    {
436
        OUT << " = ";
437
        if (node->getIsDefault())
438
            OUT << "default(";
439
        printExpression(node, "value",indent);
440
        if (node->getIsDefault())
441
            OUT << ")";
442
    }
443
    else if (node->getIsDefault())
444
    {
445
        OUT << " = default";
446
    }
447

    
448
    if (indent)
449
        OUT << ";" << getRightComment(node);
450
    else
451
        OUT << ";";
452
}
453

    
454
void NED2Generator::doProperty(PropertyElement *node, const char *indent, bool islast, const char *sep)
455
{
456
    if (!node->getIsImplicit())
457
    {
458
        // if sep==NULL, print as standalone property (with indent and ";"), otherwise as inline property
459
        OUT << getBannerComment(node, indent);
460
        if (!sep && indent)
461
            OUT << indent;
462
        if (sep)
463
            OUT << " ";
464
        OUT << "@" << node->getName();
465
        if (!opp_isempty(node->getIndex()))
466
            OUT << "[" << node->getIndex() << "]";
467
        const char *subindent = indent ? increaseIndent(indent) : DEFAULTINDENT;
468
        if (node->getFirstChildWithTag(NED_PROPERTY_KEY))
469
        {
470
            OUT << "(";
471
            generateChildrenWithType(node, NED_PROPERTY_KEY, subindent, "; ");
472
            OUT << ")";
473
        }
474
        if (!sep && !indent)
475
            OUT << ";";
476
        else if (!sep)
477
            OUT << ";" << getRightComment(node);
478
    }
479
}
480

    
481
void NED2Generator::doPropertyKey(PropertyKeyElement *node, const char *indent, bool islast, const char *sep)
482
{
483
    OUT << node->getName();
484
    if (node->getFirstChildWithTag(NED_LITERAL))
485
    {
486
        if (!opp_isempty(node->getName()))
487
            OUT << "=";
488
        generateChildrenWithType(node, NED_LITERAL, increaseIndent(indent),",");
489
    }
490
    if (!islast && sep)
491
        OUT << (sep ? sep : "");
492
}
493

    
494
void NED2Generator::doGates(GatesElement *node, const char *indent, bool islast, const char *)
495
{
496
    OUT << getBannerComment(node, indent);
497
    OUT << indent << "gates:" << getRightComment(node);
498
    generateChildren(node, increaseIndent(indent));
499
}
500

    
501
void NED2Generator::doGate(GateElement *node, const char *indent, bool islast, const char *)
502
{
503
    OUT << getBannerComment(node, indent);
504
    OUT << indent;
505
    switch (node->getType())
506
    {
507
        case NED_GATETYPE_NONE:   break;
508
        case NED_GATETYPE_INPUT:  OUT << "input "; break;
509
        case NED_GATETYPE_OUTPUT: OUT << "output "; break;
510
        case NED_GATETYPE_INOUT:  OUT << "inout "; break;
511
        default: INTERNAL_ERROR0(node, "wrong type");
512
    }
513
    OUT << node->getName();
514
    if (node->getIsVector() && !hasExpression(node,"vector-size"))
515
        OUT << "[]";
516
    printOptVector(node, "vector-size",indent);
517

    
518
    generateChildrenWithType(node, NED_PROPERTY, increaseIndent(indent), " ");
519
    OUT << ";" << getRightComment(node);;
520
}
521

    
522
void NED2Generator::doTypes(TypesElement *node, const char *indent, bool islast, const char *)
523
{
524
    OUT << getBannerComment(node, indent);
525
    OUT << indent << "types:" << getRightComment(node);
526
    generateChildren(node, increaseIndent(indent));
527
}
528

    
529
void NED2Generator::doSubmodules(SubmodulesElement *node, const char *indent, bool islast, const char *)
530
{
531
    OUT << getBannerComment(node, indent);
532
    OUT << indent << "submodules:" << getRightComment(node);
533
    generateChildren(node, increaseIndent(indent));
534
}
535

    
536
void NED2Generator::doSubmodule(SubmoduleElement *node, const char *indent, bool islast, const char *)
537
{
538
    OUT << getBannerComment(node, indent);
539
    OUT << indent << node->getName();
540
    printOptVector(node, "vector-size",indent);
541
    OUT << ": ";
542

    
543
    if (!opp_isempty(node->getLikeType()))
544
    {
545
        // "like" version
546
        OUT << "<";
547
        printExpression(node, "like-param", indent); // this (incidentally) also works if like-param contains a property (ie. starts with "@")
548
        OUT << ">";
549
        OUT << " like " << node->getLikeType();
550
    }
551
    else
552
    {
553
        // "like"-less
554
        OUT << node->getType();
555
    }
556

    
557
    if (!node->getFirstChildWithTag(NED_PARAMETERS) && !node->getFirstChildWithTag(NED_GATES))
558
    {
559
        OUT << ";" << getTrailingComment(node);
560
    }
561
    else
562
    {
563
        OUT << " {" << getRightComment(node);
564
        generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
565
        generateChildrenWithType(node, NED_GATES, increaseIndent(indent));
566
        OUT << indent << "}" << getTrailingComment(node);
567
    }
568
}
569

    
570
void NED2Generator::doConnections(ConnectionsElement *node, const char *indent, bool islast, const char *)
571
{
572
    OUT << getBannerComment(node, indent);
573
    if (node->getAllowUnconnected()) {
574
        OUT << indent << "connections allowunconnected:" << getRightComment(node);
575
    } else {
576
        OUT << indent << "connections:" << getRightComment(node);
577
    }
578
    generateChildren(node, increaseIndent(indent));
579
}
580

    
581
void NED2Generator::doConnection(ConnectionElement *node, const char *indent, bool islast, const char *)
582
{
583
    // direction
584
    const char *arrow;
585
    bool srcfirst;
586
    switch (node->getArrowDirection())
587
    {
588
        case NED_ARROWDIR_L2R:   arrow = " -->"; srcfirst = true; break;
589
        case NED_ARROWDIR_R2L:   arrow = " <--"; srcfirst = false; break;
590
        case NED_ARROWDIR_BIDIR: arrow = " <-->"; srcfirst = true; break;
591
        default: INTERNAL_ERROR0(node, "wrong arrow-dir");
592
    }
593

    
594
    OUT << getBannerComment(node, indent);
595

    
596
    // print src
597
    OUT << indent;
598
    if (srcfirst)
599
        printConnectionGate(node, node->getSrcModule(), "src-module-index", node->getSrcGate(), "src-gate-index", node->getSrcGatePlusplus(), node->getSrcGateSubg(), indent);
600
    else
601
        printConnectionGate(node, node->getDestModule(), "dest-module-index", node->getDestGate(), "dest-gate-index", node->getDestGatePlusplus(), node->getDestGateSubg(), indent);
602

    
603
    // arrow
604
    OUT << arrow;
605

    
606
    // print channel spec
607
    ChannelSpecElement *channelSpecNode = (ChannelSpecElement *)node->getFirstChildWithTag(NED_CHANNEL_SPEC);
608
    if (channelSpecNode && !isEmptyChannelSpec(channelSpecNode))
609
    {
610
        generateChildrenWithType(node, NED_CHANNEL_SPEC, indent);
611
        OUT << arrow;
612
    }
613

    
614
    // print dest
615
    OUT << " ";
616
    if (srcfirst)
617
        printConnectionGate(node, node->getDestModule(), "dest-module-index", node->getDestGate(), "dest-gate-index", node->getDestGatePlusplus(), node->getDestGateSubg(), indent);
618
    else
619
        printConnectionGate(node, node->getSrcModule(), "src-module-index", node->getSrcGate(), "src-gate-index", node->getSrcGatePlusplus(), node->getSrcGateSubg(), indent);
620

    
621
    // print loops and conditions
622
    if (node->getFirstChildWithTag(NED_LOOP) || node->getFirstChildWithTag(NED_CONDITION))
623
    {
624
        OUT << " ";
625
        int tags[] = {NED_LOOP, NED_CONDITION, NED_NULL};
626
        generateChildrenWithTypes(node, tags, increaseIndent(indent), ", ");
627
    }
628
    OUT << ";" << getRightComment(node);
629
}
630

    
631
bool NED2Generator::isEmptyChannelSpec(ChannelSpecElement *node)
632
{
633
    if (!opp_isempty(node->getType()) || !opp_isempty(node->getLikeType()) || !opp_isempty(node->getLikeParam()))
634
        return false;
635
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
636
        if (child->getTagCode() != NED_COMMENT)
637
            return false;
638
    return true;
639
}
640

    
641
void NED2Generator::doChannelSpec(ChannelSpecElement *node, const char *indent, bool islast, const char *)
642
{
643
    if (!opp_isempty(node->getLikeType()))
644
    {
645
        // "like" version
646
        OUT << " <";
647
        printExpression(node, "like-param", indent); // this (incidentally) also works if like-param contains a property (ie. starts with "@")
648
        OUT << ">";
649
        OUT << " like " << node->getLikeType();
650
    }
651
    else if (!opp_isempty(node->getType()))
652
    {
653
        // concrete channel type
654
        OUT << " " << node->getType();
655
    }
656

    
657
    if (node->getFirstChildWithTag(NED_PARAMETERS))
658
    {
659
        OUT << " { ";
660
        generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
661
        OUT << " }";
662
    }
663
}
664

    
665
void NED2Generator::doConnectionGroup(ConnectionGroupElement *node, const char *indent, bool islast, const char *)
666
{
667
    OUT << getBannerComment(node, indent);
668
    if (node->getFirstChildWithTag(NED_LOOP) || node->getFirstChildWithTag(NED_CONDITION))
669
    {
670
        OUT << indent;
671
        int tags[] = {NED_LOOP, NED_CONDITION, NED_NULL};
672
        generateChildrenWithTypes(node, tags, increaseIndent(indent), ", ");
673
    }
674

    
675
    OUT << " {" << getRightComment(node);
676
    generateChildrenWithType(node, NED_CONNECTION, increaseIndent(indent));
677
    OUT << indent << "}" << getTrailingComment(node);
678
}
679

    
680
void NED2Generator::doLoop(LoopElement *node, const char *indent, bool islast, const char *sep)
681
{
682
    OUT << "for " << node->getParamName() << "=";
683
    printExpression(node, "from-value",indent);
684
    OUT << "..";
685
    printExpression(node, "to-value",indent);
686

    
687
    if (!islast)
688
        OUT << (sep ? sep : "");
689
}
690

    
691
void NED2Generator::doCondition(ConditionElement *node, const char *indent, bool islast, const char *sep)
692
{
693
    OUT << "if ";
694
    printExpression(node, "condition",indent);
695
    if (!islast)
696
        OUT << (sep ? sep : "");
697
}
698

    
699
void NED2Generator::printConnectionGate(NEDElement *conn, const char *modname, const char *modindexattr,
700
                                        const char *gatename, const char *gateindexattr, bool isplusplus,
701
                                        int gatesubg, const char *indent)
702
{
703
    if (!opp_isempty(modname)) {
704
        OUT << modname;
705
        printOptVector(conn, modindexattr,indent);
706
        OUT << ".";
707
    }
708

    
709
    OUT << gatename;
710
    switch (gatesubg)
711
    {
712
        case NED_SUBGATE_NONE: break;
713
        case NED_SUBGATE_I: OUT << "$i"; break;
714
        case NED_SUBGATE_O: OUT << "$o"; break;
715
        default: INTERNAL_ERROR0(conn, "wrong subg type");
716
    }
717
    if (isplusplus)
718
        OUT << "++";
719
    else
720
        printOptVector(conn, gateindexattr,indent);
721
}
722

    
723
void NED2Generator::doExpression(ExpressionElement *node, const char *indent, bool islast, const char *)
724
{
725
    generateChildren(node,indent);
726
}
727

    
728
int NED2Generator::getOperatorPrecedence(const char *op, int args)
729
{
730
    //
731
    // this method should always contain the same precendence rules as ebnf.y
732
    //
733

    
734
    if (args==3)
735
    {
736
        // %left '?' ':'
737
        if (!strcmp(op,"?:")) return 1;
738
        INTERNAL_ERROR1(NULL, "getOperatorPrecedence(): unknown tertiary operator '%s'", op);
739
    }
740

    
741
    if (args==2)
742
    {
743
        // %left OR
744
        if (!strcmp(op,"||")) return 2;
745
        // %left XOR
746
        if (!strcmp(op,"##")) return 3;
747
        // %left AND
748
        if (!strcmp(op,"&&")) return 4;
749

    
750
        // %left EQ NE GT GE LS LE
751
        if (!strcmp(op,"==")) return 5;
752
        if (!strcmp(op,"!=")) return 5;
753
        if (!strcmp(op,"<"))  return 5;
754
        if (!strcmp(op,">"))  return 5;
755
        if (!strcmp(op,"<=")) return 5;
756
        if (!strcmp(op,">=")) return 5;
757

    
758
        // %left BIN_OR
759
        if (!strcmp(op,"|"))  return 6;
760
        // %left BIN_XOR
761
        if (!strcmp(op,"#"))  return 7;
762
        // %left BIN_AND
763
        if (!strcmp(op,"&"))  return 8;
764

    
765
        // %left SHIFT_LEFT SHIFT_RIGHT
766
        if (!strcmp(op,"<<")) return 9;
767
        if (!strcmp(op,">>")) return 9;
768

    
769
        // %left PLUS MIN
770
        if (!strcmp(op,"+"))  return 10;
771
        if (!strcmp(op,"-"))  return 10;
772

    
773
        // %left MUL DIV MOD
774
        if (!strcmp(op,"*"))  return 11;
775
        if (!strcmp(op,"/"))  return 11;
776
        if (!strcmp(op,"%"))  return 11;
777

    
778
        // %right EXP
779
        if (!strcmp(op,"^"))  return 12;
780
        INTERNAL_ERROR1(NULL, "getOperatorPrecedence(): unknown binary operator '%s'", op);
781
    }
782

    
783
    if (args==1)
784
    {
785
        // %left UMIN NOT BIN_COMPL
786
        if (!strcmp(op,"-"))  return 13;
787
        if (!strcmp(op,"!"))  return 13;
788
        if (!strcmp(op,"~"))  return 13;
789
        INTERNAL_ERROR1(NULL, "getOperatorPrecedence(): unknown unary operator '%s'", op);
790
    }
791

    
792
    INTERNAL_ERROR1(NULL, "getOperatorPrecedence(): bad number of args: %d", args);
793
    return -1;
794
}
795

    
796
bool NED2Generator::isOperatorLeftAssoc(const char *op)
797
{
798
    // only exponentiation is right assoc, all others are left assoc
799
    if (!strcmp(op,"^")) return false;
800
    return true;
801
}
802

    
803
void NED2Generator::doOperator(OperatorElement *node, const char *indent, bool islast, const char *)
804
{
805
    NEDElement *op1 = node->getFirstChild();
806
    NEDElement *op2 = op1 ? op1->getNextSibling() : NULL;
807
    NEDElement *op3 = op2 ? op2->getNextSibling() : NULL;
808

    
809
    if (!op2)
810
    {
811
        // unary
812
        OUT << node->getName();
813
        generateNedItem(op1,indent,false,NULL);
814
    }
815
    else if (!op3)
816
    {
817
        // binary
818
        int prec = getOperatorPrecedence(node->getName(), 2);
819
        //bool leftassoc = isOperatorLeftAssoc(node->getName());
820

    
821
        bool needsParen = false;
822
        bool spacious = (prec<=2);  // we want spaces around &&, ||, ##
823

    
824
        NEDElement *parent = node->getParent();
825
        if (parent && parent->getTagCode()==NED_OPERATOR)
826
        {
827
            OperatorElement *parentop = (OperatorElement *)parent;
828
            int parentprec = getOperatorPrecedence(parentop->getName(), parentop->getNumChildren());
829
            if (parentprec>prec)
830
            {
831
                needsParen = true;
832
            }
833
            else if (parentprec==prec)
834
            {
835
                // TBD can be refined (make use of associativity & precedence rules)
836
                needsParen = true;
837
            }
838
        }
839

    
840
        if (needsParen) OUT << "(";
841
        generateNedItem(op1,indent,false,NULL);
842
        if (spacious)
843
            OUT << " " << node->getName() << " ";
844
        else
845
            OUT << node->getName();
846
        generateNedItem(op2,indent,false,NULL);
847
        if (needsParen) OUT << ")";
848
    }
849
    else
850
    {
851
        // tertiary
852
        bool needsParen = true; // TBD can be refined
853
        bool spacious = true; // TBD can be refined
854

    
855
        if (needsParen) OUT << "(";
856
        generateNedItem(op1,indent,false,NULL);
857
        OUT << (spacious ? " ? " : "?");
858
        generateNedItem(op2,indent,false,NULL);
859
        OUT << (spacious ? " : " : ":");
860
        generateNedItem(op3,indent,false,NULL);
861
        if (needsParen) OUT << ")";
862
    }
863
}
864

    
865
void NED2Generator::doFunction(FunctionElement *node, const char *indent, bool islast, const char *)
866
{
867
    if (!strcmp(node->getName(), "index")) {
868
        OUT << node->getName();  // 'index' doesn't need parentheses
869
        return;
870
    }
871

    
872
    OUT << node->getName() << "(";
873
    for (NEDElement *child=node->getFirstChild(); child; child = child->getNextSibling())
874
    {
875
        if (child != node->getFirstChild())
876
            OUT << ", ";
877
        generateNedItem(child, indent, false, NULL);
878
    }
879
    OUT << ")";
880
}
881

    
882
void NED2Generator::doIdent(IdentElement *node, const char *indent, bool islast, const char *)
883
{
884
    if (!opp_isempty(node->getModule())) {
885
        OUT << node->getModule();
886
        if (node->getFirstChild()) {
887
            OUT << "[";
888
            generateChildren(node,indent,NULL);
889
            OUT << "]";
890
        }
891
        OUT << ".";
892
    }
893

    
894
    OUT << node->getName();
895
}
896

    
897
void NED2Generator::doLiteral(LiteralElement *node, const char *indent, bool islast, const char *sep)
898
{
899
    if (!opp_isempty(node->getText()))
900
    {
901
        OUT << node->getText();
902
    }
903
    else
904
    {
905
        // fallback: when original text is not present, use value
906
        if (node->getType()==NED_CONST_STRING)
907
            OUT << opp_quotestr(node->getValue());
908
        else
909
            OUT << node->getValue();
910
    }
911
    if (!islast)
912
        OUT << (sep ? sep : "");
913
}
914

    
915
void NED2Generator::doMsgFile(MsgFileElement *node, const char *indent, bool, const char *)
916
{
917
    OUT << getBannerComment(node, indent);
918
    generateChildren(node, indent);
919
}
920

    
921
void NED2Generator::doNamespace(NamespaceElement *node, const char *indent, bool islast, const char *)
922
{
923
    OUT << getBannerComment(node, indent);
924
    OUT << indent << "namespace " << node->getName() << ";" << getRightComment(node);
925
    OUT << getTrailingComment(node);
926
}
927

    
928
void NED2Generator::doCplusplus(CplusplusElement *node, const char *indent, bool islast, const char *)
929
{
930
    OUT << getBannerComment(node, indent);
931
    OUT << indent << "cplusplus {{" << node->getBody() << "}}" << getRightComment(node);
932
    OUT << getTrailingComment(node);
933
}
934

    
935
void NED2Generator::doStructDecl(StructDeclElement *node, const char *indent, bool islast, const char *)
936
{
937
    OUT << getBannerComment(node, indent);
938
    OUT << indent << "struct " << node->getName() << ";" << getRightComment(node);
939
    OUT << getTrailingComment(node);
940
}
941

    
942
void NED2Generator::doClassDecl(ClassDeclElement *node, const char *indent, bool islast, const char *)
943
{
944
    OUT << getBannerComment(node, indent);
945
    OUT << indent << "class ";
946
    if (!node->getIsCobject()) OUT << "noncobject ";
947
    OUT << node->getName();
948
    if (!opp_isempty(node->getExtendsName())) OUT << " extends " << node->getExtendsName();
949
    OUT << ";" << getRightComment(node);
950
    OUT << getTrailingComment(node);
951
}
952

    
953
void NED2Generator::doMessageDecl(MessageDeclElement *node, const char *indent, bool islast, const char *)
954
{
955
    OUT << getBannerComment(node, indent);
956
    OUT << indent << "message " << node->getName() << ";" << getRightComment(node);
957
    OUT << getTrailingComment(node);
958
}
959

    
960
void NED2Generator::doPacketDecl(PacketDeclElement *node, const char *indent, bool islast, const char *)
961
{
962
    OUT << getBannerComment(node, indent);
963
    OUT << indent << "packet " << node->getName() << ";" << getRightComment(node);
964
    OUT << getTrailingComment(node);
965
}
966

    
967
void NED2Generator::doEnumDecl(EnumDeclElement *node, const char *indent, bool islast, const char *)
968
{
969
    OUT << getBannerComment(node, indent);
970
    OUT << indent << "enum ";
971
    OUT << node->getName() << ";" << getRightComment(node);
972
    OUT << getTrailingComment(node);
973
}
974

    
975
void NED2Generator::doEnum(EnumElement *node, const char *indent, bool islast, const char *)
976
{
977
    OUT << getBannerComment(node, indent);
978
    OUT << indent << "enum " << node->getName();
979
    if (!opp_isempty(node->getExtendsName()))
980
        OUT << " extends " << node->getExtendsName();
981
    OUT << getRightComment(node);
982
    OUT << indent << "{\n";
983
    generateChildren(node, increaseIndent(indent));
984
    OUT << indent << "}";
985
    OUT << getTrailingComment(node);
986
}
987

    
988
void NED2Generator::doEnumFields(EnumFieldsElement *node, const char *indent, bool islast, const char *)
989
{
990
    OUT << getBannerComment(node, indent);
991
    OUT << getRightComment(node);
992
    generateChildren(node, indent);
993
}
994

    
995
void NED2Generator::doEnumField(EnumFieldElement *node, const char *indent, bool islast, const char *)
996
{
997
    OUT << getBannerComment(node, indent);
998
    OUT << indent << node->getName();
999
    if (!opp_isempty(node->getValue()))
1000
        OUT << " = " << node->getValue();
1001
    OUT << ";" << getRightComment(node);
1002
}
1003

    
1004
void NED2Generator::doMessage(MessageElement *node, const char *indent, bool islast, const char *)
1005
{
1006
    OUT << getBannerComment(node, indent);
1007
    OUT << indent << "message " << node->getName();
1008
    if (!opp_isempty(node->getExtendsName()))
1009
        OUT << " extends " << node->getExtendsName();
1010
    OUT << getRightComment(node);
1011
    OUT << indent << "{\n";
1012
    doMsgClassOrStructBody(node, indent);
1013
    OUT << indent << "}";
1014
    OUT << getTrailingComment(node);
1015
}
1016

    
1017
void NED2Generator::doPacket(PacketElement *node, const char *indent, bool islast, const char *)
1018
{
1019
    OUT << getBannerComment(node, indent);
1020
    OUT << indent << "packet " << node->getName();
1021
    if (!opp_isempty(node->getExtendsName()))
1022
        OUT << " extends " << node->getExtendsName();
1023
    OUT << getRightComment(node);
1024
    OUT << indent << "{\n";
1025
    doMsgClassOrStructBody(node, indent);
1026
    OUT << indent << "}";
1027
    OUT << getTrailingComment(node);
1028
}
1029

    
1030
void NED2Generator::doClass(ClassElement *node, const char *indent, bool islast, const char *)
1031
{
1032
    OUT << getBannerComment(node, indent);
1033
    OUT << indent << "class " << node->getName();
1034
    if (!opp_isempty(node->getExtendsName()))
1035
        OUT << " extends " << node->getExtendsName();
1036
    OUT << getRightComment(node);
1037
    OUT << indent << "{\n";
1038
    doMsgClassOrStructBody(node, indent);
1039
    OUT << indent << "}";
1040
    OUT << getTrailingComment(node);
1041
}
1042

    
1043
void NED2Generator::doStruct(StructElement *node, const char *indent, bool islast, const char *)
1044
{
1045
    OUT << getBannerComment(node, indent);
1046
    OUT << indent << "struct " << node->getName();
1047
    if (!opp_isempty(node->getExtendsName()))
1048
        OUT << " extends " << node->getExtendsName();
1049
    OUT << getRightComment(node);
1050
    OUT << indent << "{\n";
1051
    doMsgClassOrStructBody(node, indent);
1052
    OUT << indent << "}" << getTrailingComment(node);
1053
}
1054

    
1055
void NED2Generator::doMsgClassOrStructBody(NEDElement *node, const char *indent)
1056
{
1057
    // "node" must be a PacketElement, MessageElement, ClassElement or StructElement
1058
    generateChildren(node, increaseIndent(indent));
1059

    
1060
    //if (msgfileVersion!=1)
1061
    //    generateChildren(node, increaseIndent(indent)); // 4.x syntax
1062
    //else
1063
    //{
1064
    //     // old (3.x) syntax
1065
    //     if (node->getFirstChildWithTag(NED_PROPERTY))
1066
    //     {
1067
    //         OUT << increaseIndent(indent) << "properties:\n";
1068
    //         generateChildrenWithType(node, NED_PROPERTY, increaseIndent(increaseIndent(indent)));
1069
    //     }
1070
    //     if (node->getFirstChildWithTag(NED_FIELD))
1071
    //     {
1072
    //         OUT << increaseIndent(indent) << "fields:\n";
1073
    //         generateChildrenWithType(node, NED_FIELD, increaseIndent(increaseIndent(indent)));
1074
    //     }
1075
    //}
1076
}
1077

    
1078
void NED2Generator::doField(FieldElement *node, const char *indent, bool islast, const char *)
1079
{
1080
    OUT << getBannerComment(node, indent);
1081
    OUT << indent;
1082
    if (node->getIsAbstract())
1083
        OUT << "abstract ";
1084
    if (node->getIsReadonly())
1085
        OUT << "readonly ";
1086
    if (!opp_isempty(node->getDataType()))
1087
        OUT << node->getDataType() << " ";
1088
    OUT << node->getName();
1089
    if (node->getIsVector() && !opp_isempty(node->getVectorSize()))
1090
        OUT << "[" << node->getVectorSize() << "]";
1091
    else if (node->getIsVector())
1092
        OUT << "[]";
1093
    const char *subindent = indent ? increaseIndent(indent) : DEFAULTINDENT;
1094
    generateChildrenWithType(node, NED_PROPERTY, subindent, " ");
1095
    if (!opp_isempty(node->getDefaultValue()))
1096
        OUT << " = " << node->getDefaultValue();
1097
    OUT << ";" << getRightComment(node);
1098
}
1099

    
1100
void NED2Generator::doComment(CommentElement *node, const char *indent, bool islast, const char *)
1101
{
1102
    // ignore here: comments are taken care of individually where they occur
1103
}
1104

    
1105
//---------------------------------------------------------------------------
1106

    
1107
void NED2Generator::generateNedItem(NEDElement *node, const char *indent, bool islast, const char *arg)
1108
{
1109
    // dispatch
1110
    int tagcode = node->getTagCode();
1111
    switch (tagcode)
1112
    {
1113
        case NED_FILES:
1114
            doFiles((FilesElement *)node, indent, islast, arg); break;
1115
        case NED_NED_FILE:
1116
            doNedFile((NedFileElement *)node, indent, islast, arg); break;
1117
        case NED_PACKAGE:
1118
            doPackage((PackageElement *)node, indent, islast, arg); break;
1119
        case NED_IMPORT:
1120
            doImport((ImportElement *)node, indent, islast, arg); break;
1121
        case NED_PROPERTY_DECL:
1122
            doPropertyDecl((PropertyDeclElement *)node, indent, islast, arg); break;
1123
        case NED_EXTENDS:
1124
            doExtends((ExtendsElement *)node, indent, islast, arg); break;
1125
        case NED_INTERFACE_NAME:
1126
            doInterfaceName((InterfaceNameElement *)node, indent, islast, arg); break;
1127
        case NED_SIMPLE_MODULE:
1128
            doSimpleModule((SimpleModuleElement *)node, indent, islast, arg); break;
1129
        case NED_MODULE_INTERFACE:
1130
            doModuleInterface((ModuleInterfaceElement *)node, indent, islast, arg); break;
1131
        case NED_COMPOUND_MODULE:
1132
            doCompoundModule((CompoundModuleElement *)node, indent, islast, arg); break;
1133
        case NED_CHANNEL_INTERFACE:
1134
            doChannelInterface((ChannelInterfaceElement *)node, indent, islast, arg); break;
1135
        case NED_CHANNEL:
1136
            doChannel((ChannelElement *)node, indent, islast, arg); break;
1137
        case NED_PARAMETERS:
1138
            doParameters((ParametersElement *)node, indent, islast, arg); break;
1139
        case NED_PARAM:
1140
            doParam((ParamElement *)node, indent, islast, arg); break;
1141
        case NED_PROPERTY:
1142
            doProperty((PropertyElement *)node, indent, islast, arg); break;
1143
        case NED_PROPERTY_KEY:
1144
            doPropertyKey((PropertyKeyElement *)node, indent, islast, arg); break;
1145
        case NED_GATES:
1146
            doGates((GatesElement *)node, indent, islast, arg); break;
1147
        case NED_GATE:
1148
            doGate((GateElement *)node, indent, islast, arg); break;
1149
        case NED_TYPES:
1150
            doTypes((TypesElement *)node, indent, islast, arg); break;
1151
        case NED_SUBMODULES:
1152
            doSubmodules((SubmodulesElement *)node, indent, islast, arg); break;
1153
        case NED_SUBMODULE:
1154
            doSubmodule((SubmoduleElement *)node, indent, islast, arg); break;
1155
        case NED_CONNECTIONS:
1156
            doConnections((ConnectionsElement *)node, indent, islast, arg); break;
1157
        case NED_CONNECTION:
1158
            doConnection((ConnectionElement *)node, indent, islast, arg); break;
1159
        case NED_CHANNEL_SPEC:
1160
            doChannelSpec((ChannelSpecElement *)node, indent, islast, arg); break;
1161
        case NED_CONNECTION_GROUP:
1162
            doConnectionGroup((ConnectionGroupElement *)node, indent, islast, arg); break;
1163
        case NED_LOOP:
1164
            doLoop((LoopElement *)node, indent, islast, arg); break;
1165
        case NED_CONDITION:
1166
            doCondition((ConditionElement *)node, indent, islast, arg); break;
1167
        case NED_EXPRESSION:
1168
            doExpression((ExpressionElement *)node, indent, islast, arg); break;
1169
        case NED_OPERATOR:
1170
            doOperator((OperatorElement *)node, indent, islast, arg); break;
1171
        case NED_FUNCTION:
1172
            doFunction((FunctionElement *)node, indent, islast, arg); break;
1173
        case NED_IDENT:
1174
            doIdent((IdentElement *)node, indent, islast, arg); break;
1175
        case NED_LITERAL:
1176
            doLiteral((LiteralElement *)node, indent, islast, arg); break;
1177

    
1178
        case NED_MSG_FILE:
1179
            doMsgFile((MsgFileElement *)node, indent, islast, arg); break;
1180
        case NED_NAMESPACE:
1181
            doNamespace((NamespaceElement *)node, indent, islast, arg); break;
1182
        case NED_CPLUSPLUS:
1183
            doCplusplus((CplusplusElement *)node, indent, islast, arg); break;
1184
        case NED_STRUCT_DECL:
1185
            doStructDecl((StructDeclElement *)node, indent, islast, arg); break;
1186
        case NED_CLASS_DECL:
1187
            doClassDecl((ClassDeclElement *)node, indent, islast, arg); break;
1188
        case NED_MESSAGE_DECL:
1189
            doMessageDecl((MessageDeclElement *)node, indent, islast, arg); break;
1190
        case NED_PACKET_DECL:
1191
            doPacketDecl((PacketDeclElement *)node, indent, islast, arg); break;
1192
        case NED_ENUM_DECL:
1193
            doEnumDecl((EnumDeclElement *)node, indent, islast, arg); break;
1194
        case NED_ENUM:
1195
            doEnum((EnumElement *)node, indent, islast, arg); break;
1196
        case NED_ENUM_FIELDS:
1197
            doEnumFields((EnumFieldsElement *)node, indent, islast, arg); break;
1198
        case NED_ENUM_FIELD:
1199
            doEnumField((EnumFieldElement *)node, indent, islast, arg); break;
1200
        case NED_MESSAGE:
1201
            doMessage((MessageElement *)node, indent, islast, arg); break;
1202
        case NED_PACKET:
1203
            doPacket((PacketElement *)node, indent, islast, arg); break;
1204
        case NED_CLASS:
1205
            doClass((ClassElement *)node, indent, islast, arg); break;
1206
        case NED_STRUCT:
1207
            doStruct((StructElement *)node, indent, islast, arg); break;
1208
        case NED_FIELD:
1209
            doField((FieldElement *)node, indent, islast, arg); break;
1210
        case NED_COMMENT:
1211
            doComment((CommentElement *)node, indent, islast, arg); break;
1212
        default:
1213
            INTERNAL_ERROR1(node, "generateNedItem(): unknown tag '%s'", node->getTagName());
1214
    }
1215
}
1216

    
1217
NAMESPACE_END