PageRenderTime 48ms CodeModel.GetById 25ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/omnetpp-4.1/src/nedxml/nedparser.cc

https://bitbucket.org/indigopony/omnetproject
C++ | 272 lines | 221 code | 28 blank | 23 comment | 23 complexity | b436b9e5c88b0a3b05e95d55d8139a87 MD5 | raw file
  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
 34NAMESPACE_BEGIN
 35
 36#define MAGIC_PREFIX   "@expr@"  // note: must agree with ned2.lex
 37
 38NEDParser *np;
 39
 40//--------
 41
 42const 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
101NEDParser::NEDParser(NEDErrorStore *e)
102{
103    nedsource = NULL;
104    parseexpr = true;
105    storesrc = false;
106    errors = e;
107}
108
109NEDParser::~NEDParser()
110{
111    delete nedsource;
112}
113
114NEDElement *NEDParser::parseNEDFile(const char *osfname, const char *fname)
115{
116    if (!loadFile(osfname, fname))
117        return NULL;
118    return parseNED();
119}
120
121NEDElement *NEDParser::parseNEDText(const char *nedtext, const char *fname)
122{
123    if (!loadText(nedtext, fname))
124        return NULL;
125    return parseNED();
126}
127
128NEDElement *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
135NEDElement *NEDParser::parseMSGFile(const char *osfname, const char *fname)
136{
137    if (!loadFile(osfname, fname))
138        return NULL;
139    return parseMSG();
140}
141
142NEDElement *NEDParser::parseMSGText(const char *nedtext, const char *fname)
143{
144    if (!loadText(nedtext,fname))
145        return NULL;
146    return parseMSG();
147}
148
149bool 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
174bool 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
191NEDElement *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
200NEDElement *NEDParser::parseMSG()
201{
202    errors->clear();
203    return ::doParseMSG2(this, nedsource->getFullText());
204}
205
206bool 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
263void 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
270NAMESPACE_END
271
272