PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms 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
Possible License(s): BSD-3-Clause, AGPL-1.0, GPL-2.0, Apache-2.0, JSON
  1. //==========================================================================
  2. // NEDPARSER.CC - part of
  3. //
  4. // OMNeT++/OMNEST
  5. // Discrete System Simulation in C++
  6. //
  7. //==========================================================================
  8. /*--------------------------------------------------------------*
  9. Copyright (C) 2002-2008 Andras Varga
  10. Copyright (C) 2006-2008 OpenSim Ltd.
  11. This file is distributed WITHOUT ANY WARRANTY. See the file
  12. `license' for details on this and other legal matters.
  13. *--------------------------------------------------------------*/
  14. #include <assert.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <time.h>
  19. #include <sstream>
  20. #include <string>
  21. #include "nedparser.h"
  22. #include "nedfilebuffer.h"
  23. #include "nedelements.h"
  24. #include "nederror.h"
  25. #include "opp_ctype.h"
  26. #include "nedyydefs.h"
  27. NAMESPACE_BEGIN
  28. #define MAGIC_PREFIX "@expr@" // note: must agree with ned2.lex
  29. NEDParser *np;
  30. //--------
  31. const char *NEDParser::getBuiltInDeclarations()
  32. {
  33. return
  34. "package ned;\n"
  35. "@namespace(\"\");\n"
  36. "\n"
  37. "channel IdealChannel\n"
  38. "{\n"
  39. " @class(cIdealChannel);\n"
  40. "}\n"
  41. "\n"
  42. "channel DelayChannel\n"
  43. "{\n"
  44. " @class(cDelayChannel);\n"
  45. " @signal[messageSent](type=cMessage);\n"
  46. " @signal[messageDiscarded](type=cMessage);\n"
  47. " @statistic[messages](source=\"constant1(messageSent)\";record=count?;interpolationmode=none);\n"
  48. " @statistic[messagesDiscarded](source=\"constant1(messageDiscarded)\";record=count?;interpolationmode=none);\n"
  49. " bool disabled = default(false);\n"
  50. " double delay = default(0s) @unit(s); // propagation delay\n"
  51. "}\n"
  52. "\n"
  53. "channel DatarateChannel\n"
  54. "{\n"
  55. " @class(cDatarateChannel);\n"
  56. " @signal[channelBusy](type=\"int\");\n"
  57. " @signal[messageSent](type=cMessage);\n"
  58. " @signal[messageDiscarded](type=cMessage);\n"
  59. " @statistic[busy](source=channelBusy;record=vector?;interpolationmode=sample-hold);\n"
  60. " @statistic[utilization](source=\"timeavg(channelBusy)\";record=last?);\n"
  61. " @statistic[packets](source=\"constant1(messageSent)\";record=count?;interpolationmode=none);\n"
  62. " @statistic[packetBytes](source=\"packetBytes(messageSent)\";record=sum?;unit=B;interpolationmode=none);\n"
  63. " @statistic[packetsDiscarded](source=\"constant1(messageDiscarded)\";record=count?;interpolationmode=none);\n"
  64. " @statistic[throughput](source=\"sumPerDuration(packetBits(messageSent))\";record=last?;unit=bps);\n"
  65. " bool disabled = default(false);\n"
  66. " double delay = default(0s) @unit(s); // propagation delay\n"
  67. " double datarate = default(0bps) @unit(bps); // bits per second; 0=infinite\n"
  68. " double ber = default(0); // bit error rate (BER)\n"
  69. " double per = default(0); // packet error rate (PER)\n"
  70. "}\n"
  71. "\n"
  72. "moduleinterface IBidirectionalChannel\n"
  73. "{\n"
  74. " gates:\n"
  75. " inout a;\n"
  76. " inout b;\n"
  77. "}\n"
  78. "\n"
  79. "moduleinterface IUnidirectionalChannel\n"
  80. "{\n"
  81. " gates:\n"
  82. " input i;\n"
  83. " output o;\n"
  84. "}\n"
  85. ;
  86. }
  87. //--------
  88. NEDParser::NEDParser(NEDErrorStore *e)
  89. {
  90. nedsource = NULL;
  91. parseexpr = true;
  92. storesrc = false;
  93. errors = e;
  94. }
  95. NEDParser::~NEDParser()
  96. {
  97. delete nedsource;
  98. }
  99. NEDElement *NEDParser::parseNEDFile(const char *osfname, const char *fname)
  100. {
  101. if (!loadFile(osfname, fname))
  102. return NULL;
  103. return parseNED();
  104. }
  105. NEDElement *NEDParser::parseNEDText(const char *nedtext, const char *fname)
  106. {
  107. if (!loadText(nedtext, fname))
  108. return NULL;
  109. return parseNED();
  110. }
  111. NEDElement *NEDParser::parseNEDExpression(const char *nedexpression)
  112. {
  113. parseexpr = true;
  114. std::string source = std::string(MAGIC_PREFIX) + "\n" + nedexpression;
  115. return parseNEDText(source.c_str(), "buffer");
  116. }
  117. NEDElement *NEDParser::parseMSGFile(const char *osfname, const char *fname)
  118. {
  119. if (!loadFile(osfname, fname))
  120. return NULL;
  121. return parseMSG();
  122. }
  123. NEDElement *NEDParser::parseMSGText(const char *nedtext, const char *fname)
  124. {
  125. if (!loadText(nedtext,fname))
  126. return NULL;
  127. return parseMSG();
  128. }
  129. bool NEDParser::loadFile(const char *osfname, const char *fname)
  130. {
  131. if (!fname)
  132. fname = osfname;
  133. // init class members
  134. if (nedsource) delete nedsource;
  135. nedsource = new NEDFileBuffer();
  136. filename = fname;
  137. errors->clear();
  138. // resolve "~" in file name
  139. char osfname2[1000];
  140. if (osfname[0]=='~') {
  141. sprintf(osfname2, "%s%s", getenv("HOME"), osfname+1);
  142. } else {
  143. strcpy(osfname2, osfname);
  144. }
  145. // load whole file into memory
  146. if (!nedsource->readFile(osfname2))
  147. {errors->addError("", "cannot read %s", fname); return false;}
  148. return true;
  149. }
  150. bool NEDParser::loadText(const char *nedtext, const char *fname)
  151. {
  152. if (!fname)
  153. fname = "buffer";
  154. // init vars
  155. if (nedsource) delete nedsource;
  156. nedsource = new NEDFileBuffer();
  157. filename = fname;
  158. errors->clear();
  159. // prepare nedsource object
  160. if (!nedsource->setData(nedtext))
  161. {errors->addError("", "unable to allocate work memory"); return false;}
  162. return true;
  163. }
  164. NEDElement *NEDParser::parseNED()
  165. {
  166. errors->clear();
  167. if (guessIsNEDInNewSyntax(nedsource->getFullText()))
  168. return ::doParseNED2(this, nedsource->getFullText());
  169. else
  170. return ::doParseNED1(this, nedsource->getFullText());
  171. }
  172. NEDElement *NEDParser::parseMSG()
  173. {
  174. errors->clear();
  175. return ::doParseMSG2(this, nedsource->getFullText());
  176. }
  177. bool NEDParser::guessIsNEDInNewSyntax(const char *txt)
  178. {
  179. // first, remove all comments and string literals
  180. char *buf = new char [strlen(txt)+1];
  181. const char *s;
  182. char *d;
  183. bool whitespaceOnly = true;
  184. for (s=txt, d=buf; *s; )
  185. {
  186. if (*s=='/' && *(s+1)=='/') {
  187. // if there's a comment, skip rest of the line
  188. s += 2;
  189. while (*s && *s!='\r' && *s!='\n')
  190. s++;
  191. }
  192. else if (*s=='"') {
  193. // leave out string literals as well
  194. s++;
  195. while (*s && *s!='\r' && *s!='\n' && *s!='"')
  196. if (*s++=='\\')
  197. s++;
  198. if (*s=='"')
  199. s++;
  200. }
  201. else {
  202. if (*s && !opp_isspace(*s))
  203. whitespaceOnly = false;
  204. // copy everything else
  205. *d++ = *s++;
  206. }
  207. }
  208. *d = '\0';
  209. // Only in NED2 are curly braces {} and "@" allowed and widely used.
  210. //
  211. bool containsNED2Chars = strchr(buf,'{') || strchr(buf,'}') || strchr(buf,'@');
  212. // If needed, check whether it contains the keyword "package";
  213. // it is only used in NED2. We have to search "whole words only",
  214. // so plain strstr() is not enough.
  215. // Note: this is not bulletproof, because NED2 keywords were not
  216. // reserved in NED1.
  217. //
  218. bool containsPackageKeyword=false;
  219. if (!containsNED2Chars)
  220. for (const char *s = strstr(buf,"package"); s!=NULL; s = strstr(s+1,"package"))
  221. if (opp_isspace(s[strlen("package")]) && (s==buf || opp_isspace(s[-1])))
  222. {containsPackageKeyword=true; break;}
  223. // cleanup
  224. delete [] buf;
  225. return whitespaceOnly || containsNED2Chars || containsPackageKeyword;
  226. }
  227. void NEDParser::error(const char *msg, int line)
  228. {
  229. std::stringstream os;
  230. os << filename << ":" << line;
  231. errors->addError(os.str().c_str(), "%s", msg);
  232. }
  233. NAMESPACE_END