Statistics
| Branch: | Revision:

root / src / nedxml / ned1generator.cc @ 68da4f12

History | View | Annotate | Download (42 KB)

1
//==========================================================================
2
//  NED1GENERATOR.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 "ned1generator.h"
22
#include "stringutil.h"
23
#include "nedutil.h"
24

    
25
NAMESPACE_BEGIN
26

    
27
using std::ostream;
28

    
29
#define DEFAULTINDENT "            "
30

    
31
#define NED2FEATURE  "NED2 feature unsupported in NED1: "
32

    
33

    
34
void generateNED1(ostream& out, NEDElement *node, NEDErrorStore *e)
35
{
36
    NED1Generator nedgen(e);
37
    nedgen.generate(out, node, "");
38
}
39

    
40
//-----------------------------------------
41

    
42
#define OUT  (*outp)
43

    
44
NED1Generator::NED1Generator(NEDErrorStore *e)
45
{
46
    outp = NULL;
47
    indentsize = 4;
48
    errors = e;
49
}
50

    
51
NED1Generator::~NED1Generator()
52
{
53
}
54

    
55
void NED1Generator::setIndentSize(int indentsiz)
56
{
57
    indentsize = indentsiz;
58
}
59

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

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

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

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

    
87
const char *NED1Generator::decreaseIndent(const char *indent)
88
{
89
    return indent + indentsize;
90
}
91

    
92
//---------------------------------------------------------------------------
93

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

    
100
//---------------------------------------------------------------------------
101

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

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

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

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

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

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

    
144
//---------------------------------------------------------------------------
145

    
146
void NED1Generator::printInheritance(NEDElement *node, const char *indent)
147
{
148
    // for network...endnetwork, print " : type", otherwise warn for any "extends" or "like"
149
    if (_isNetwork(node))
150
    {
151
        if (node->getNumChildrenWithTag(NED_INTERFACE_NAME)>0)
152
            errors->addWarning(node, NED2FEATURE "inheritance");
153
        NEDElement *extendsNode = node->getFirstChildWithTag(NED_EXTENDS);
154
        if (!extendsNode)
155
            errors->addWarning(node, "network must extend a module type");
156
        else
157
            OUT << " : " << ((ExtendsElement *)extendsNode)->getName();
158
    }
159
    else if (node->getFirstChildWithTag(NED_EXTENDS) || node->getFirstChildWithTag(NED_INTERFACE_NAME))
160
    {
161
        errors->addWarning(node, NED2FEATURE "inheritance");
162
    }
163
}
164

    
165
bool NED1Generator::hasExpression(NEDElement *node, const char *attr)
166
{
167
    if (!opp_isempty(node->getAttribute(attr)))
168
    {
169
        return true;
170
    }
171
    else
172
    {
173
        for (ExpressionElement *expr=(ExpressionElement *)node->getFirstChildWithTag(NED_EXPRESSION); expr; expr=expr->getNextExpressionSibling())
174
            if (!opp_isempty(expr->getTarget()) && !strcmp(expr->getTarget(),attr))
175
                return true;
176
        return false;
177
    }
178
}
179

    
180
void NED1Generator::printExpression(NEDElement *node, const char *attr, const char *indent)
181
{
182
    if (!opp_isempty(node->getAttribute(attr)))
183
    {
184
        OUT << node->getAttribute(attr);
185
    }
186
    else
187
    {
188
        for (ExpressionElement *expr=(ExpressionElement *)node->getFirstChildWithTag(NED_EXPRESSION); expr; expr=expr->getNextExpressionSibling())
189
            if (!opp_isempty(expr->getTarget()) && !strcmp(expr->getTarget(),attr))
190
                generateNedItem(expr, indent, false, NULL);
191
    }
192
}
193

    
194
void NED1Generator::printOptVector(NEDElement *node, const char *attr, const char *indent)
195
{
196
    if (hasExpression(node,attr))
197
    {
198
        OUT << "[";
199
        printExpression(node,attr,indent);
200
        OUT << "]";
201
    }
202
}
203

    
204
//---------------------------------------------------------------------------
205

    
206
static const char *getComment(NEDElement *node, const char *locId)
207
{
208
    CommentElement *comment = (CommentElement *)node->getFirstChildWithAttribute(NED_COMMENT, "locid", locId);
209
    return (comment && !opp_isempty(comment->getContent())) ? comment->getContent() : NULL;
210
}
211

    
212
static std::string formatComment(const char *comment, const char *indent, const char *defaultValue)
213
{
214
    if (!comment || !comment[0])
215
        return defaultValue;
216

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

    
235
        curLine = nextLine[0] ? nextLine+1 : nextLine; // +1: skip newline
236
    }
237
    return ret;
238
}
239

    
240
std::string NED1Generator::concatInnerComments(NEDElement *node)
241
{
242
    std::string ret;
243
    for (NEDElement *child=node->getFirstChildWithTag(NED_COMMENT); child; child = child->getNextSiblingWithTag(NED_COMMENT))
244
    {
245
        CommentElement *comment = (CommentElement *)child;
246
        if (!strcmp(comment->getLocid(), "inner"))
247
            ret += comment->getContent();
248
    }
249
    return ret;
250
}
251

    
252
std::string NED1Generator::getBannerComment(NEDElement *node, const char *indent)
253
{
254
    const char *comment = getComment(node, "banner");
255
    std::string innerComments = concatInnerComments(node);
256
    return formatComment(comment, indent, "") + formatComment(innerComments.c_str(), indent, "");
257
}
258

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

    
265
std::string NED1Generator::getInlineRightComment(NEDElement *node)
266
{
267
    const char *comment = getComment(node, "right");
268
    return formatComment(comment, NULL, " ");
269
}
270

    
271
std::string NED1Generator::getTrailingComment(NEDElement *node)
272
{
273
    const char *comment = getComment(node, "trailing");
274
    return formatComment(comment, NULL, "\n");
275
}
276

    
277
//---------------------------------------------------------------------------
278

    
279
void NED1Generator::doNedfiles(FilesElement *node, const char *indent, bool, const char *)
280
{
281
    generateChildren(node, indent);
282
}
283

    
284
void NED1Generator::doNedfile(NedFileElement *node, const char *indent, bool, const char *)
285
{
286
    OUT << getBannerComment(node, indent);
287
    generateChildren(node, indent);
288
}
289

    
290
void NED1Generator::doImport(ImportElement *node, const char *indent, bool islast, const char *)
291
{
292
    // In NED2 style, it would be just these 2 lines:
293
    //OUT << getBannerComment(node, indent);
294
    //OUT << indent << "import \"" << node->getFilename() << "\";" << getRightComment(node);
295

    
296
    // but we want to merge all imports under a single "import" keyword
297
    if (!node->getPrevSibling() || node->getPrevSibling()->getTagCode()!=NED_IMPORT)
298
    {
299
        OUT << indent << "import\n";
300
    }
301

    
302
    OUT << getBannerComment(node, indent);
303
    bool isLastImport = !node->getNextSibling() || node->getNextSibling()->getTagCode()!=NED_IMPORT;
304
    OUT << increaseIndent(indent) << "\"" << node->getImportSpec() << "\"";
305
    OUT << (isLastImport ? ";" : ",") << getRightComment(node);
306
}
307

    
308
void NED1Generator::doPropertyDecl(PropertyDeclElement *node, const char *indent, bool islast, const char *)
309
{
310
    errors->addWarning(node, NED2FEATURE "properties");
311
}
312

    
313
void NED1Generator::doExtends(ExtendsElement *node, const char *indent, bool islast, const char *sep)
314
{
315
    INTERNAL_ERROR0(node,"should never come here");
316
}
317

    
318
void NED1Generator::doInterfaceName(InterfaceNameElement *node, const char *indent, bool islast, const char *sep)
319
{
320
    INTERNAL_ERROR0(node,"should never come here");
321
}
322

    
323
void NED1Generator::doSimpleModule(SimpleModuleElement *node, const char *indent, bool islast, const char *)
324
{
325
    OUT << getBannerComment(node, indent);
326
    OUT << indent << "simple " << node->getName();
327
    printInheritance(node, indent);
328
    OUT << getRightComment(node);
329

    
330
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
331
    generateChildrenWithType(node, NED_GATES, increaseIndent(indent));
332

    
333
    OUT << indent << "endsimple" << getTrailingComment(node);
334
}
335

    
336
void NED1Generator::doModuleInterface(ModuleInterfaceElement *node, const char *indent, bool islast, const char *)
337
{
338
    errors->addWarning(node, NED2FEATURE "interfaces");
339
}
340

    
341
void NED1Generator::doCompoundModule(CompoundModuleElement *node, const char *indent, bool islast, const char *)
342
{
343
    OUT << getBannerComment(node, indent);
344
    OUT << indent << (_isNetwork(node) ? "network" : "module") << " " << node->getName();
345
    printInheritance(node, indent);
346
    OUT << getRightComment(node);
347

    
348
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
349
    generateChildrenWithType(node, NED_GATES, increaseIndent(indent));
350
    generateChildrenWithType(node, NED_TYPES, increaseIndent(indent));
351
    generateChildrenWithType(node, NED_SUBMODULES, increaseIndent(indent));
352
    generateChildrenWithType(node, NED_CONNECTIONS, increaseIndent(indent));
353

    
354
    PropertyElement *displayProp;
355
    std::string dispstr = getDisplayStringOf(node, displayProp);
356
    if (!dispstr.empty())
357
    {
358
        try {
359
            dispstr = DisplayStringUtil::toOldBackgroundDisplayString(opp_parsequotedstr(dispstr.c_str()).c_str());
360
            OUT << getBannerComment(displayProp, increaseIndent(indent));
361
            OUT << increaseIndent(indent) << "display: " << opp_quotestr(dispstr.c_str()) << ";" << getRightComment(displayProp);
362
        }
363
        catch (std::exception& e) {
364
            errors->addWarning(node, opp_stringf("error converting display string: %s", e.what()).c_str());
365
        }
366
    }
367

    
368
    OUT << indent << (_isNetwork(node) ? "endnetwork" : "endmodule") << getTrailingComment(node);
369
}
370

    
371
void NED1Generator::doChannelInterface(ChannelInterfaceElement *node, const char *indent, bool islast, const char *)
372
{
373
    errors->addWarning(node, NED2FEATURE "channel interfaces");
374
}
375

    
376
void NED1Generator::doChannel(ChannelElement *node, const char *indent, bool islast, const char *)
377
{
378
    OUT << getBannerComment(node, indent);
379
    OUT << indent << "channel ";
380
    OUT << node->getName();
381
    printInheritance(node, indent);
382
    OUT << getRightComment(node);
383

    
384
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
385

    
386
    OUT << indent << "endchannel" << getTrailingComment(node);
387
}
388

    
389
void NED1Generator::doParameters(ParametersElement *node, const char *indent, bool islast, const char *)
390
{
391
    // in NED-1, parameters followed different syntaxes at different places
392
    int parentTag = node->getParent()->getTagCode();
393
    if (parentTag==NED_SUBMODULE || _isNetwork(node->getParent()))
394
        doSubstParameters(node, indent);
395
    else if (parentTag==NED_SIMPLE_MODULE || parentTag==NED_COMPOUND_MODULE)
396
        doModuleParameters(node, indent);
397
    else if (parentTag==NED_CHANNEL)
398
        doChannelParameters(node, indent);
399
    else if (parentTag==NED_CHANNEL_SPEC)
400
        doConnectionAttributes(node, indent);
401
    else
402
        INTERNAL_ERROR0(node,"unexpected parameters section");
403
}
404

    
405
void NED1Generator::doModuleParameters(ParametersElement *node, const char *indent)
406
{
407
    OUT << getBannerComment(node, indent);
408
    if (node->getFirstChildWithTag(NED_PARAM))
409
        OUT << indent << "parameters:" << getRightComment(node);
410

    
411
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
412
    {
413
        int childTag = child->getTagCode();
414
        if (childTag==NED_COMMENT)
415
            ; // ignore whitespace
416
        else if (childTag==NED_PROPERTY)
417
            doProperty((PropertyElement *)child, increaseIndent(indent), false, NULL);
418
        else if (childTag==NED_PARAM)
419
            doModuleParam((ParamElement *)child, increaseIndent(indent), child->getNextSiblingWithTag(NED_PARAM)==NULL, NULL);
420
        else
421
            INTERNAL_ERROR0(node,"unexpected element");
422
    }
423
}
424

    
425
void NED1Generator::doSubstParameters(ParametersElement *node, const char *indent)
426
{
427
    OUT << getBannerComment(node, indent);
428
    if (node->getFirstChildWithTag(NED_PARAM))
429
        OUT << indent << "parameters:" << getRightComment(node);
430

    
431
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
432
    {
433
        int childTag = child->getTagCode();
434
        if (childTag==NED_COMMENT)
435
            ; //ignore
436
        else if (childTag==NED_PROPERTY)
437
            doProperty((PropertyElement *)child, increaseIndent(indent), false, NULL);
438
        else if (childTag==NED_PARAM)
439
            doSubstParam((ParamElement *)child, increaseIndent(indent), child->getNextSiblingWithTag(NED_PARAM)==NULL, NULL);
440
        else
441
            INTERNAL_ERROR0(node,"unexpected element");
442
    }
443
}
444

    
445
void NED1Generator::doChannelParameters(ParametersElement *node, const char *indent)
446
{
447
    // only "delay", "error", "datarate" parameters need to be recognized
448
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
449
    {
450
        int childTag = child->getTagCode();
451
        if (childTag==NED_COMMENT)
452
            ; //ignore
453
        else if (childTag==NED_PROPERTY)
454
            doProperty((PropertyElement *)child, indent, false, NULL);
455
        else if (childTag==NED_PARAM)
456
            doChannelParam((ParamElement *)child, indent);
457
        else
458
            INTERNAL_ERROR0(node,"unexpected element");
459
    }
460
}
461

    
462
void NED1Generator::doConnectionAttributes(ParametersElement *node, const char *indent)
463
{
464
    // only "delay", "error", "datarate" parameters need to be recognized
465
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
466
    {
467
        int childTag = child->getTagCode();
468
        if (childTag==NED_COMMENT)
469
            ; //ignore
470
        else if (childTag==NED_PROPERTY)
471
            doProperty((PropertyElement *)child, indent, false, NULL);
472
        else if (childTag==NED_PARAM)
473
            doChannelParam((ParamElement *)child, NULL);
474
        else
475
            INTERNAL_ERROR0(node,"unexpected element");
476
    }
477
}
478

    
479
void NED1Generator::doChannelParam(ParamElement *node, const char *indent)
480
{
481
    // this is used both in channel definitions and in connections
482
    OUT << getBannerComment(node, indent);
483
    const char *name = node->getName();
484
    if (strcmp(name, "delay")==0 || strcmp(name, "ber")==0 || strcmp(name, "datarate")==0)
485
    {
486
        // indent==NULL means no indent and no new line at end (but a space at front)
487
        if (strcmp(name, "ber")==0) name="error";  // "error" got renamed to "ber" in 4.0
488
        OUT << (indent ? indent : " ");
489
        OUT << name << " ";
490
        printExpression(node, "value", indent);
491
        if (indent)
492
            OUT << ";" << getRightComment(node);
493
    }
494
    else
495
    {
496
        errors->addWarning(node, NED2FEATURE "channel parameters other than delay, error and datarate");
497
    }
498
}
499

    
500
void NED1Generator::doParam(ParamElement *node, const char *indent, bool islast, const char *)
501
{
502
    // we use doModuleParam() and doSubstParam() instead
503
    // doParameters() ensures we never get here
504
    INTERNAL_ERROR0(node, "should never get here");
505
}
506

    
507
void NED1Generator::doModuleParam(ParamElement *node, const char *indent, bool islast, const char *)
508
{
509
    const char *parType = NULL;
510
    switch (node->getType())
511
    {
512
        case NED_PARTYPE_NONE:   break;
513
        case NED_PARTYPE_DOUBLE: case NED_PARTYPE_INT:
514
                                 parType = node->getIsVolatile() ? "numeric" : "numeric const"; break;
515
        case NED_PARTYPE_STRING: parType = "string"; break;
516
        case NED_PARTYPE_BOOL:   parType = "bool"; break;
517
        case NED_PARTYPE_XML:    parType = "xml"; break;
518
        default: INTERNAL_ERROR0(node, "wrong type");
519
    }
520

    
521
    OUT << getBannerComment(node, indent);
522
    OUT << indent << node->getName();
523
    if (parType!=NULL)
524
        OUT << ": " << parType;
525

    
526
    if (node->getIsPattern())
527
        errors->addWarning(node, NED2FEATURE "assignment by pattern matching");
528

    
529
    if (hasExpression(node,"value"))
530
        errors->addWarning(node, NED2FEATURE "assignment in parameter declaration");
531

    
532
    const char *subindent = indent ? increaseIndent(indent) : DEFAULTINDENT;
533
    generateChildrenWithType(node, NED_PROPERTY, subindent, " ");
534

    
535
    OUT << (islast ? ";" : ",") << getRightComment(node);
536
}
537

    
538
const char *NED1Generator::getPromptTextOf(ParamElement *param)
539
{
540
    PropertyElement *promptProp = (PropertyElement *)param->getFirstChildWithAttribute(NED_PROPERTY, "name", "prompt");
541
    if (!promptProp)
542
        return NULL;
543
    PropertyKeyElement *propKey = (PropertyKeyElement *)promptProp->getFirstChildWithAttribute(NED_PROPERTY_KEY, "name", "");
544
    if (!propKey)
545
        return NULL;
546
    LiteralElement *literal = (LiteralElement *)propKey->getFirstChildWithTag(NED_LITERAL);
547
    if (!literal)
548
        return NULL;
549
    return literal->getText(); //FIXME use value if text is not present!!!! (see doLiteral())
550
}
551

    
552
void NED1Generator::doSubstParam(ParamElement *node, const char *indent, bool islast, const char *)
553
{
554
    if (node->getType()!=NED_PARTYPE_NONE)
555
        errors->addWarning(node, NED2FEATURE "defining new parameter for a submodule");
556

    
557
    OUT << getBannerComment(node, indent);
558
    OUT << indent << node->getName() << " = ";
559

    
560
    if (node->getIsPattern())
561
        errors->addWarning(node, NED2FEATURE "assignment by pattern matching");
562

    
563
    if (!hasExpression(node, "value"))
564
    {
565
        if (node->getIsDefault())
566
            errors->addWarning(node, NED2FEATURE "'parameter=default' syntax");
567
        OUT << "input";
568
    }
569
    else if (!node->getIsDefault())
570
    {
571
        printExpression(node, "value", indent);
572
    }
573
    else
574
    {
575
        OUT << "input(";
576
        printExpression(node, "value", indent);
577
        const char *prompt = getPromptTextOf(node);
578
        if (prompt)
579
            OUT << ", " << prompt;
580
        OUT << ")";
581
    }
582

    
583
    generateChildrenWithType(node, NED_PROPERTY, increaseIndent(indent), " ");
584

    
585
    OUT << (islast ? ";" : ",") << getRightComment(node);
586
}
587

    
588
void NED1Generator::doProperty(PropertyElement *node, const char *indent, bool islast, const char *sep)
589
{
590
    // issue a warning, except for those few accepted occurrences of @display and @prompt
591
    // note: no code needs to be generated here, that is done separately
592
    if (strcmp(node->getName(), "display")==0)
593
    {
594
        // must be submodule->parameters->property, module->parameters->property or
595
        // connection->chanspec->parameters->property
596
        NEDElement *grandparent = node->getParent() ? node->getParent()->getParent() : NULL;
597
        if (!grandparent || (grandparent->getTagCode()!=NED_SUBMODULE && grandparent->getTagCode()!=NED_COMPOUND_MODULE && grandparent->getTagCode()!=NED_CHANNEL_SPEC))
598
            errors->addWarning(node, NED2FEATURE "@display may occur on submodules, connections and compound modules only");
599
    }
600
    else if (strcmp(node->getName(), "prompt")==0)
601
    {
602
        int parentTag = node->getParent()->getTagCode();
603
        if (parentTag!=NED_PARAM)
604
            errors->addWarning(node, NED2FEATURE "@prompt may occur in submodule parameter assigments and networks only");
605
    }
606
    else
607
        errors->addWarning(node, NED2FEATURE "property (except @display and @prompt)");
608
}
609

    
610
void NED1Generator::doPropertyKey(PropertyKeyElement *node, const char *indent, bool islast, const char *sep)
611
{
612
    INTERNAL_ERROR0(node,"should never come here");
613
}
614

    
615
void NED1Generator::doGates(GatesElement *node, const char *indent, bool islast, const char *)
616
{
617
    // in NED-1, distingish between "gates" and "gatesizes"
618
    int parentTag = node->getParent()->getTagCode();
619
    if (parentTag==NED_SUBMODULE)
620
        doSubmoduleGatesizes(node, indent);
621
    else if (parentTag==NED_SIMPLE_MODULE || parentTag==NED_COMPOUND_MODULE)
622
        doModuleGates(node, indent);
623
    else
624
        INTERNAL_ERROR0(node,"unexpected gates section");
625
}
626

    
627
void NED1Generator::doModuleGates(GatesElement *node, const char *indent)
628
{
629
    OUT << getBannerComment(node, indent);
630
    if (node->getFirstChildWithTag(NED_GATE))
631
        OUT << indent << "gates:" << getRightComment(node);
632

    
633
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
634
    {
635
        int childTag = child->getTagCode();
636
        if (childTag==NED_COMMENT)
637
            ; // ignore whitespace
638
        else if (childTag==NED_GATE)
639
            doModuleGate((GateElement *)child, increaseIndent(indent), child->getNextSiblingWithTag(NED_GATE)==NULL, NULL);
640
        else
641
            INTERNAL_ERROR0(node,"unexpected element");
642
    }
643
}
644

    
645
void NED1Generator::doSubmoduleGatesizes(GatesElement *node, const char *indent)
646
{
647
    OUT << getBannerComment(node, indent);
648
    OUT << indent << "gatesizes:" << getRightComment(node);
649

    
650
    for (NEDElement *child=node->getFirstChild(); child; child=child->getNextSibling())
651
    {
652
        int childTag = child->getTagCode();
653
        if (childTag==NED_COMMENT)
654
            ; //ignore
655
        else if (childTag==NED_GATE)
656
            doGatesize((GateElement *)child, increaseIndent(indent), child->getNextSiblingWithTag(NED_GATE)==NULL, NULL);
657
        else
658
            INTERNAL_ERROR0(node,"unexpected element");
659
    }
660
}
661

    
662
void NED1Generator::doGate(GateElement *node, const char *indent, bool islast, const char *)
663
{
664
    // we use doModuleGate()/doGatesize() instead
665
    // doGates() ensures we never get here
666
    INTERNAL_ERROR0(node, "should never get here");
667
}
668

    
669
void NED1Generator::doModuleGate(GateElement *node, const char *indent, bool islast, const char *)
670
{
671
    OUT << getBannerComment(node, indent);
672
    OUT << indent;
673
    switch (node->getType())
674
    {
675
        case NED_GATETYPE_INPUT:  OUT << "in: "; break;
676
        case NED_GATETYPE_OUTPUT: OUT << "out: "; break;
677
        case NED_GATETYPE_INOUT:  errors->addWarning(node, NED2FEATURE "inout gate"); break;
678
        case NED_GATETYPE_NONE:   errors->addWarning(node, NED2FEATURE "missing gate type"); break;
679
        default: INTERNAL_ERROR0(node, "wrong type");
680
    }
681
    OUT << node->getName();
682
    if (node->getIsVector())
683
        OUT << "[]";
684
    if (hasExpression(node, "vector-size"))
685
        errors->addWarning(node, NED2FEATURE "gate vector size in gate declaration");
686
    generateChildrenWithType(node, NED_PROPERTY, increaseIndent(indent), " ");
687
    OUT << ";" << getRightComment(node);
688
}
689

    
690
void NED1Generator::doGatesize(GateElement *node, const char *indent, bool islast, const char *)
691
{
692
    OUT << getBannerComment(node, indent);
693
    OUT << indent;
694
    if (node->getType()!=NED_GATETYPE_NONE)
695
        errors->addWarning(node, NED2FEATURE "declaring new gates for submodules");
696
    OUT << node->getName();
697
    if (!hasExpression(node, "vector-size"))
698
        errors->addWarning(node, NED2FEATURE "missing gate size");
699
    printOptVector(node, "vector-size",indent);
700

    
701
    generateChildrenWithType(node, NED_PROPERTY, increaseIndent(indent), " ");
702
    OUT << (islast ? ";" : ",") << getRightComment(node);
703
}
704

    
705
void NED1Generator::doTypes(TypesElement *node, const char *indent, bool islast, const char *)
706
{
707
    errors->addWarning(node, NED2FEATURE "inner type");
708
}
709

    
710
void NED1Generator::doSubmodules(SubmodulesElement *node, const char *indent, bool islast, const char *)
711
{
712
    OUT << getBannerComment(node, indent);
713
    OUT << indent << "submodules:" << getRightComment(node);
714
    generateChildren(node, increaseIndent(indent));
715
}
716

    
717
void NED1Generator::doSubmodule(SubmoduleElement *node, const char *indent, bool islast, const char *)
718
{
719
    OUT << getBannerComment(node, indent);
720
    OUT << indent << node->getName() << ": ";
721

    
722
    if (!opp_isempty(node->getLikeType()))
723
    {
724
        // "like" version
725
        printExpression(node, "like-param", indent); // this (incidentally) also works if like-param contains a property (ie. starts with "@")
726
        printOptVector(node, "vector-size",indent);
727
        OUT << " like " << node->getLikeType();
728
    }
729
    else
730
    {
731
        // "like"-less
732
        OUT << node->getType();
733
        printOptVector(node, "vector-size",indent);
734
    }
735
    OUT << ";" << getRightComment(node);
736

    
737
    generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
738
    generateChildrenWithType(node, NED_GATES, increaseIndent(indent));
739

    
740
    PropertyElement *displayProp;
741
    std::string dispstr = getDisplayStringOf(node, displayProp);
742
    if (!dispstr.empty())
743
    {
744
        try {
745
            dispstr = DisplayStringUtil::toOldSubmoduleDisplayString(opp_parsequotedstr(dispstr.c_str()).c_str());
746
            OUT << getBannerComment(displayProp, increaseIndent(indent));
747
            OUT << increaseIndent(indent) << "display: " << opp_quotestr(dispstr.c_str()) << ";" << getRightComment(displayProp);
748
        }
749
        catch (std::exception& e) {
750
            errors->addWarning(node, opp_stringf("error converting display string: %s", e.what()).c_str());
751
        }
752
    }
753
}
754

    
755
std::string NED1Generator::getDisplayStringOf(NEDElement *node, PropertyElement *&outDisplayProp)
756
{
757
    // node must be a module, submodule or a connection-spec
758
    outDisplayProp = NULL;
759
    ParametersElement *parameters = (ParametersElement *)node->getFirstChildWithTag(NED_PARAMETERS);
760
    if (!parameters)
761
        return "";
762
    PropertyElement *displayProp = (PropertyElement *)parameters->getFirstChildWithAttribute(NED_PROPERTY, "name", "display");
763
    if (!displayProp)
764
        return "";
765
    PropertyKeyElement *propKey = (PropertyKeyElement *)displayProp->getFirstChildWithAttribute(NED_PROPERTY_KEY, "name", "");
766
    if (!propKey)
767
        return "";
768
    LiteralElement *literal = (LiteralElement *)propKey->getFirstChildWithTag(NED_LITERAL);
769
    if (!literal)
770
        return "";
771
    outDisplayProp = displayProp;
772
    return !opp_isempty(literal->getText()) ? literal->getText() : opp_quotestr(literal->getValue());
773
}
774

    
775
void NED1Generator::doConnections(ConnectionsElement *node, const char *indent, bool islast, const char *)
776
{
777
    OUT << getBannerComment(node, indent);
778
    if (node->getAllowUnconnected())
779
        OUT << indent << "connections nocheck:" << getRightComment(node);
780
    else
781
        OUT << indent << "connections:" << getRightComment(node);
782
    generateChildren(node, increaseIndent(indent));
783
}
784

    
785
void NED1Generator::doConnection(ConnectionElement *node, const char *indent, bool islast, const char *)
786
{
787
    //  direction
788
    const char *arrow;
789
    bool srcfirst;
790
    switch (node->getArrowDirection())
791
    {
792
        case NED_ARROWDIR_L2R:   arrow = " -->"; srcfirst = true; break;
793
        case NED_ARROWDIR_R2L:   arrow = " <--"; srcfirst = false; break;
794
        case NED_ARROWDIR_BIDIR: errors->addWarning(node, NED2FEATURE "two-way connection");
795
                                 arrow = " <-->"; srcfirst = true; break;
796
        default: INTERNAL_ERROR0(node, "wrong arrow-dir");
797
    }
798

    
799
    OUT << getBannerComment(node, indent);
800

    
801
    // print src
802
    OUT << indent;
803
    if (srcfirst)
804
        printConnectionGate(node, node->getSrcModule(), "src-module-index", node->getSrcGate(), "src-gate-index", node->getSrcGatePlusplus(), node->getSrcGateSubg(), indent);
805
    else
806
        printConnectionGate(node, node->getDestModule(), "dest-module-index", node->getDestGate(), "dest-gate-index", node->getDestGatePlusplus(), node->getDestGateSubg(), indent);
807

    
808
    // arrow
809
    OUT << arrow;
810

    
811
    // print channel attributes
812
    if (node->getFirstChildWithTag(NED_CHANNEL_SPEC))
813
    {
814
        generateChildrenWithType(node, NED_CHANNEL_SPEC, indent, arrow);
815
    }
816

    
817
    // print dest
818
    OUT << " ";
819
    if (srcfirst)
820
        printConnectionGate(node, node->getDestModule(), "dest-module-index", node->getDestGate(), "dest-gate-index", node->getDestGatePlusplus(), node->getDestGateSubg(), indent);
821
    else
822
        printConnectionGate(node, node->getSrcModule(), "src-module-index", node->getSrcGate(), "src-gate-index", node->getSrcGatePlusplus(), node->getSrcGateSubg(), indent);
823

    
824
    if (node->getFirstChildWithTag(NED_LOOP))
825
        errors->addWarning(node, NED2FEATURE "per-connection `for'");
826

    
827
    if (node->getNumChildrenWithTag(NED_CONDITION)>1)
828
        errors->addWarning(node, NED2FEATURE "more than one `if' per-connection");
829

    
830
    NEDElement *condition = node->getFirstChildWithTag(NED_CONDITION);
831
    if (condition)
832
        doCondition((ConditionElement *)condition, indent, false, NULL);
833

    
834
    // display string
835
    NEDElement *chanSpecNode = node->getFirstChildWithTag(NED_CHANNEL_SPEC);
836
    if (chanSpecNode)
837
    {
838
        PropertyElement *dummy;
839
        std::string dispstr = getDisplayStringOf(chanSpecNode, dummy);
840
        if (!dispstr.empty())
841
        {
842
            try {
843
                dispstr = DisplayStringUtil::toOldConnectionDisplayString(opp_parsequotedstr(dispstr.c_str()).c_str());
844
                OUT << " display " << opp_quotestr(dispstr.c_str());
845
            }
846
            catch (std::exception& e) {
847
                errors->addWarning(node, opp_stringf("error converting display string: %s", e.what()).c_str());
848
            }
849
        }
850
    }
851

    
852
    OUT << ";" << getRightComment(node);
853
}
854

    
855
void NED1Generator::doChannelSpec(ChannelSpecElement *node, const char *indent, bool islast, const char *arrow)
856
{
857
    NEDElement *params = node->getFirstChildWithTag(NED_PARAMETERS);
858
    bool hasParams = params && params->getFirstChildWithTag(NED_PARAM);
859

    
860
    if (!opp_isempty(node->getLikeType()))
861
    {
862
        errors->addWarning(node, NED2FEATURE "channel `like'");
863
    }
864
    else if (!opp_isempty(node->getType()))
865
    {
866
        // concrete channel type
867
        OUT << " " << node->getType() << arrow;
868

    
869
        if (hasParams)
870
            errors->addWarning(node, NED2FEATURE "channel spec with parameters");
871
    }
872
    else if (node->getFirstChildWithTag(NED_PARAMETERS))
873
    {
874
        generateChildrenWithType(node, NED_PARAMETERS, increaseIndent(indent));
875
        if (hasParams)
876
            OUT << arrow;
877
    }
878
}
879

    
880
void NED1Generator::doConnectionGroup(ConnectionGroupElement *node, const char *indent, bool islast, const char *)
881
{
882
    OUT << getBannerComment(node, indent);
883
    OUT << indent << "for ";
884
    generateChildrenWithType(node, NED_LOOP, increaseIndent(indent), ", ");
885
    OUT << " do" << getRightComment(node);
886

    
887
    generateChildrenWithType(node, NED_CONNECTION, increaseIndent(indent));
888

    
889
    OUT << indent << "endfor;" << getTrailingComment(node);
890
}
891

    
892
void NED1Generator::doLoop(LoopElement *node, const char *indent, bool islast, const char *sep)
893
{
894
    OUT << node->getParamName() << "=";
895
    printExpression(node, "from-value",indent);
896
    OUT << "..";
897
    printExpression(node, "to-value",indent);
898

    
899
    if (!islast)
900
        OUT << (sep ? sep : "");
901
}
902

    
903
void NED1Generator::doCondition(ConditionElement *node, const char *indent, bool islast, const char *sep)
904
{
905
    OUT << " if ";
906
    printExpression(node, "condition",indent);
907
    if (!islast)
908
        OUT << (sep ? sep : "");
909
}
910

    
911
void NED1Generator::printConnectionGate(NEDElement *conn, const char *modname, const char *modindexattr,
912
                                        const char *gatename, const char *gateindexattr, bool isplusplus,
913
                                        int gatesubg, const char *indent)
914
{
915
    if (!opp_isempty(modname)) {
916
        OUT << modname;
917
        printOptVector(conn, modindexattr,indent);
918
        OUT << ".";
919
    }
920

    
921
    OUT << gatename;
922
    if (isplusplus)
923
        OUT << "++";
924
    else
925
        printOptVector(conn, gateindexattr,indent);
926

    
927
    if (gatesubg!=NED_SUBGATE_NONE)
928
        errors->addWarning(conn, NED2FEATURE "subgate of inout gate");
929
}
930

    
931
void NED1Generator::doExpression(ExpressionElement *node, const char *indent, bool islast, const char *)
932
{
933
    generateChildren(node,indent);
934
}
935

    
936
int NED1Generator::getOperatorPrecedence(const char *op, int args)
937
{
938
    //
939
    // this method should always contain the same precendence rules as ebnf.y
940
    //
941

    
942
    if (args==3)
943
    {
944
        // %left '?' ':'
945
        if (!strcmp(op,"?:")) return 1;
946
    }
947

    
948
    if (args==2)
949
    {
950
        // %left OR
951
        if (!strcmp(op,"||")) return 2;
952
        // %left XOR
953
        if (!strcmp(op,"##")) return 3;
954
        // %left AND
955
        if (!strcmp(op,"&&")) return 4;
956

    
957
        // %left EQ NE GT GE LS LE
958
        if (!strcmp(op,"==")) return 5;
959
        if (!strcmp(op,"!=")) return 5;
960
        if (!strcmp(op,"<"))  return 5;
961
        if (!strcmp(op,">"))  return 5;
962
        if (!strcmp(op,"<=")) return 5;
963
        if (!strcmp(op,">=")) return 5;
964

    
965
        // %left BIN_OR
966
        if (!strcmp(op,"|"))  return 6;
967
        // %left BIN_XOR
968
        if (!strcmp(op,"#"))  return 7;
969
        // %left BIN_AND
970
        if (!strcmp(op,"&"))  return 8;
971

    
972
        // %left SHIFT_LEFT SHIFT_RIGHT
973
        if (!strcmp(op,"<<")) return 9;
974
        if (!strcmp(op,">>")) return 9;
975

    
976
        // %left PLUS MIN
977
        if (!strcmp(op,"+"))  return 10;
978
        if (!strcmp(op,"-"))  return 10;
979

    
980
        // %left MUL DIV MOD
981
        if (!strcmp(op,"*"))  return 11;
982
        if (!strcmp(op,"/"))  return 11;
983
        if (!strcmp(op,"%"))  return 11;
984

    
985
        // %right EXP
986
        if (!strcmp(op,"^"))  return 12;
987
    }
988

    
989
    if (args==1)
990
    {
991
        // %left UMIN NOT BIN_COMPL
992
        if (!strcmp(op,"-"))  return 13;
993
        if (!strcmp(op,"!"))  return 13;
994
        if (!strcmp(op,"~"))  return 13;
995
    }
996
    INTERNAL_ERROR1(NULL, "getOperatorPrecedence(): unknown operator '%s'", op);
997
    return -1;
998
}
999

    
1000
bool NED1Generator::isOperatorLeftAssoc(const char *op)
1001
{
1002
    // only exponentiation is right assoc, all others are left assoc
1003
    if (!strcmp(op,"^")) return false;
1004
    return true;
1005
}
1006

    
1007
void NED1Generator::doOperator(OperatorElement *node, const char *indent, bool islast, const char *)
1008
{
1009
    NEDElement *op1 = node->getFirstChild();
1010
    NEDElement *op2 = op1 ? op1->getNextSibling() : NULL;
1011
    NEDElement *op3 = op2 ? op2->getNextSibling() : NULL;
1012

    
1013
    if (!op2)
1014
    {
1015
        // unary
1016
        OUT << node->getName();
1017
        generateNedItem(op1,indent,false,NULL);
1018
    }
1019
    else if (!op3)
1020
    {
1021
        // binary
1022
        int prec = getOperatorPrecedence(node->getName(), 2);
1023
        //bool leftassoc = isOperatorLeftAssoc(node->getName());
1024

    
1025
        bool needsParen = false;
1026
        bool spacious = (prec<=2);  // we want spaces around &&, ||, ##
1027

    
1028
        NEDElement *parent = node->getParent();
1029
        if (parent && parent->getTagCode()==NED_OPERATOR) {
1030
            OperatorElement *parentop = (OperatorElement *)parent;
1031
            int parentprec = getOperatorPrecedence(parentop->getName(),2 ); //FIXME 2 ???
1032
            if (parentprec>prec) {
1033
                needsParen = true;
1034
            } else if (parentprec==prec) {
1035
                // TBD can be refined (make use of associativity & precedence rules)
1036
                needsParen = true;
1037
            }
1038
        }
1039

    
1040
        if (needsParen) OUT << "(";
1041
        generateNedItem(op1,indent,false,NULL);
1042
        if (spacious)
1043
            OUT << " " << node->getName() << " ";
1044
        else
1045
            OUT << node->getName();
1046
        generateNedItem(op2,indent,false,NULL);
1047
        if (needsParen) OUT << ")";
1048
    }
1049
    else
1050
    {
1051
        // tertiary
1052
        bool needsParen = true; // TBD can be refined
1053
        bool spacious = true; // TBD can be refined
1054

    
1055
        if (needsParen) OUT << "(";
1056
        generateNedItem(op1,indent,false,NULL);
1057
        OUT << (spacious ? " ? " : "?");
1058
        generateNedItem(op2,indent,false,NULL);
1059
        OUT << (spacious ? " : " : ":");
1060
        generateNedItem(op3,indent,false,NULL);
1061
        if (needsParen) OUT << ")";
1062
    }
1063
}
1064

    
1065
void NED1Generator::doFunction(FunctionElement *node, const char *indent, bool islast, const char *)
1066
{
1067
    if (!strcmp(node->getName(), "index")) {
1068
        OUT << node->getName();  // 'index' doesn't need parentheses
1069
        return;
1070
    }
1071

    
1072
    OUT << node->getName() << "(";
1073
    for (NEDElement *child=node->getFirstChild(); child; child = child->getNextSibling())
1074
    {
1075
        if (child != node->getFirstChild())
1076
            OUT << ", ";
1077
        generateNedItem(child, indent, false, NULL);
1078
    }
1079
    OUT << ")";
1080
}
1081

    
1082
void NED1Generator::doIdent(IdentElement *node, const char *indent, bool islast, const char *)
1083
{
1084
    if (!opp_isempty(node->getModule())) {
1085
        OUT << node->getModule();
1086
        printOptVector(node, "module-index", indent);
1087
        OUT << ".";
1088
    }
1089

    
1090
    OUT << node->getName();
1091
}
1092

    
1093
void NED1Generator::doLiteral(LiteralElement *node, const char *indent, bool islast, const char *)
1094
{
1095
    if (!opp_isempty(node->getText()))
1096
    {
1097
        OUT << node->getText();
1098
    }
1099
    else
1100
    {
1101
        // fallback: when original text is not present, use value
1102
        if (node->getType()==NED_CONST_STRING)
1103
            OUT << opp_quotestr(node->getValue());
1104
        else
1105
            OUT << node->getValue();
1106
    }
1107
}
1108

    
1109
//---------------------------------------------------------------------------
1110

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

    
1184
NAMESPACE_END
1185

    
1186