Project

General

Profile

Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (7.65 KB)

1
//==========================================================================
2
//  NEDPARSER.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 <assert.h>
19
#include <stdio.h>
20
#include <stdlib.h>
21
#include <string.h>
22
#include <time.h>
23
#include <sstream>
24
#include <string>
25

    
26
#include "nedparser.h"
27
#include "nedfilebuffer.h"
28
#include "nedelements.h"
29
#include "nederror.h"
30
#include "opp_ctype.h"
31

    
32
#include "nedyydefs.h"
33

    
34
NAMESPACE_BEGIN
35

    
36
#define MAGIC_PREFIX   "@expr@"  // note: must agree with ned2.lex
37

    
38
NEDParser *np;
39

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

    
42
const char *NEDParser::getBuiltInDeclarations()
43
{
44
    return
45
        "package ned;\n"
46
        "@namespace(\"\");\n"
47
        "\n"
48
        "channel IdealChannel\n"
49
        "{\n"
50
        "    @class(cIdealChannel);\n"
51
        "}\n"
52
        "\n"
53
        "channel DelayChannel\n"
54
        "{\n"
55
        "    @class(cDelayChannel);\n"
56
        "    @signal[messageSent](type=cMessage);\n"
57
        "    @signal[messageDiscarded](type=cMessage);\n"
58
        "    @statistic[messages](source=\"constant1(messageSent)\";record=count?;interpolationmode=none);\n"
59
        "    @statistic[messagesDiscarded](source=\"constant1(messageDiscarded)\";record=count?;interpolationmode=none);\n"
60
        "    bool disabled = default(false);\n"
61
        "    double delay = default(0s) @unit(s); // propagation delay\n"
62
        "}\n"
63
        "\n"
64
        "channel DatarateChannel\n"
65
        "{\n"
66
        "    @class(cDatarateChannel);\n"
67
        "    @signal[channelBusy](type=\"int\");\n"
68
        "    @signal[messageSent](type=cMessage);\n"
69
        "    @signal[messageDiscarded](type=cMessage);\n"
70
        "    @statistic[busy](source=channelBusy;record=vector?;interpolationmode=sample-hold);\n"
71
        "    @statistic[utilization](source=\"timeavg(channelBusy)\";record=last?);\n"
72
        "    @statistic[packets](source=\"constant1(messageSent)\";record=count?;interpolationmode=none);\n"
73
        "    @statistic[packetBytes](source=\"packetBytes(messageSent)\";record=sum?;unit=B;interpolationmode=none);\n"
74
        "    @statistic[packetsDiscarded](source=\"constant1(messageDiscarded)\";record=count?;interpolationmode=none);\n"
75
        "    @statistic[throughput](source=\"sumPerDuration(packetBits(messageSent))\";record=last?;unit=bps);\n"
76
        "    bool disabled = default(false);\n"
77
        "    double delay = default(0s) @unit(s); // propagation delay\n"
78
        "    double datarate = default(0bps) @unit(bps); // bits per second; 0=infinite\n"
79
        "    double ber = default(0); // bit error rate (BER)\n"
80
        "    double per = default(0); // packet error rate (PER)\n"
81
        "}\n"
82
        "\n"
83
        "moduleinterface IBidirectionalChannel\n"
84
        "{\n"
85
        "    gates:\n"
86
        "        inout a;\n"
87
        "        inout b;\n"
88
        "}\n"
89
        "\n"
90
        "moduleinterface IUnidirectionalChannel\n"
91
        "{\n"
92
        "    gates:\n"
93
        "        input i;\n"
94
        "        output o;\n"
95
        "}\n"
96
    ;
97
}
98

    
99
//--------
100

    
101
NEDParser::NEDParser(NEDErrorStore *e)
102
{
103
    nedsource = NULL;
104
    parseexpr = true;
105
    storesrc = false;
106
    errors = e;
107
}
108

    
109
NEDParser::~NEDParser()
110
{
111
    delete nedsource;
112
}
113

    
114
NEDElement *NEDParser::parseNEDFile(const char *osfname, const char *fname)
115
{
116
    if (!loadFile(osfname, fname))
117
        return NULL;
118
    return parseNED();
119
}
120

    
121
NEDElement *NEDParser::parseNEDText(const char *nedtext, const char *fname)
122
{
123
    if (!loadText(nedtext, fname))
124
        return NULL;
125
    return parseNED();
126
}
127

    
128
NEDElement *NEDParser::parseNEDExpression(const char *nedexpression)
129
{
130
    parseexpr = true;
131
    std::string source = std::string(MAGIC_PREFIX) + "\n" + nedexpression;
132
    return parseNEDText(source.c_str(), "buffer");
133
}
134

    
135
NEDElement *NEDParser::parseMSGFile(const char *osfname, const char *fname)
136
{
137
    if (!loadFile(osfname, fname))
138
        return NULL;
139
    return parseMSG();
140
}
141

    
142
NEDElement *NEDParser::parseMSGText(const char *nedtext, const char *fname)
143
{
144
    if (!loadText(nedtext,fname))
145
        return NULL;
146
    return parseMSG();
147
}
148

    
149
bool NEDParser::loadFile(const char *osfname, const char *fname)
150
{
151
    if (!fname)
152
        fname = osfname;
153

    
154
    // init class members
155
    if (nedsource) delete nedsource;
156
    nedsource = new NEDFileBuffer();
157
    filename = fname;
158
    errors->clear();
159

    
160
    // resolve "~" in file name
161
    char osfname2[1000];
162
    if (osfname[0]=='~') {
163
        sprintf(osfname2, "%s%s", getenv("HOME"), osfname+1);
164
    } else {
165
        strcpy(osfname2, osfname);
166
    }
167

    
168
    // load whole file into memory
169
    if (!nedsource->readFile(osfname2))
170
        {errors->addError("", "cannot read %s", fname); return false;}
171
    return true;
172
}
173

    
174
bool NEDParser::loadText(const char *nedtext, const char *fname)
175
{
176
    if (!fname)
177
        fname = "buffer";
178

    
179
    // init vars
180
    if (nedsource) delete nedsource;
181
    nedsource = new NEDFileBuffer();
182
    filename = fname;
183
    errors->clear();
184

    
185
    // prepare nedsource object
186
    if (!nedsource->setData(nedtext))
187
        {errors->addError("", "unable to allocate work memory"); return false;}
188
    return true;
189
}
190

    
191
NEDElement *NEDParser::parseNED()
192
{
193
    errors->clear();
194
    if (guessIsNEDInNewSyntax(nedsource->getFullText()))
195
        return ::doParseNED2(this, nedsource->getFullText());
196
    else
197
        return ::doParseNED1(this, nedsource->getFullText());
198
}
199

    
200
NEDElement *NEDParser::parseMSG()
201
{
202
    errors->clear();
203
    return ::doParseMSG2(this, nedsource->getFullText());
204
}
205

    
206
bool NEDParser::guessIsNEDInNewSyntax(const char *txt)
207
{
208
    // first, remove all comments and string literals
209
    char *buf = new char [strlen(txt)+1];
210
    const char *s;
211
    char *d;
212
    bool whitespaceOnly = true;
213
    for (s=txt, d=buf; *s; )
214
    {
215
        if (*s=='/' && *(s+1)=='/') {
216
            // if there's a comment, skip rest of the line
217
            s += 2;
218
            while (*s && *s!='\r' && *s!='\n')
219
                s++;
220
        }
221
        else if (*s=='"') {
222
            // leave out string literals as well
223
            s++;
224
            while (*s && *s!='\r' && *s!='\n' && *s!='"')
225
                if (*s++=='\\')
226
                    s++;
227
            if (*s=='"')
228
                s++;
229
        }
230
        else {
231
            if (*s && !opp_isspace(*s))
232
                whitespaceOnly = false;
233

    
234
            // copy everything else
235
            *d++ = *s++;
236

    
237
        }
238
    }
239
    *d = '\0';
240

    
241
    // Only in NED2 are curly braces {} and "@" allowed and widely used.
242
    //
243
    bool containsNED2Chars = strchr(buf,'{') || strchr(buf,'}') || strchr(buf,'@');
244

    
245
    // If needed, check whether it contains the keyword "package";
246
    // it is only used in NED2. We have to search "whole words only",
247
    // so plain strstr() is not enough.
248
    // Note: this is not bulletproof, because NED2 keywords were not
249
    // reserved in NED1.
250
    //
251
    bool containsPackageKeyword=false;
252
    if (!containsNED2Chars)
253
        for (const char *s = strstr(buf,"package"); s!=NULL; s = strstr(s+1,"package"))
254
            if (opp_isspace(s[strlen("package")]) && (s==buf || opp_isspace(s[-1])))
255
                {containsPackageKeyword=true; break;}
256

    
257
    // cleanup
258
    delete [] buf;
259

    
260
    return whitespaceOnly || containsNED2Chars || containsPackageKeyword;
261
}
262

    
263
void NEDParser::error(const char *msg, int line)
264
{
265
    std::stringstream os;
266
    os << filename << ":" << line;
267
    errors->addError(os.str().c_str(), "%s", msg);
268
}
269

    
270
NAMESPACE_END
271

    
272