CCPUScriptParser.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /****************************************************************************
  2. Copyright (C) 2013 Henry van Merode. All rights reserved.
  3. Copyright (c) 2015-2017 Chukong Technologies Inc.
  4. http://www.cocos2d-x.org
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in
  12. all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. THE SOFTWARE.
  20. ****************************************************************************/
  21. #include "CCPUScriptParser.h"
  22. NS_CC_BEGIN
  23. PUScriptParser::PUScriptParser()
  24. {
  25. }
  26. PUScriptParser::~PUScriptParser()
  27. {
  28. }
  29. void traceScriptParserCell(PUConcreteNodeList& nodes,int level)
  30. {
  31. for(const auto& node : nodes)
  32. {
  33. printf("%s,##%d\n",node->token.c_str(),level);
  34. if(node->children.size() != 0)
  35. {
  36. traceScriptParserCell(node->children,level+1);
  37. }
  38. }
  39. }
  40. void traceScriptParser(PUConcreteNodeList& nodes)
  41. {
  42. traceScriptParserCell(nodes,1);
  43. }
  44. void PUScriptParser::parse(PUConcreteNodeList& nodes,const PUScriptTokenList& tokens)
  45. {
  46. // MEMCATEGORY_GENERAL because SharedPtr can only free using that category
  47. enum{READY, OBJECT};
  48. unsigned int state = READY;
  49. PUConcreteNode *parent = 0;
  50. PUConcreteNode* node;
  51. PUScriptToken *token = 0;
  52. PUScriptTokenList::const_iterator i = tokens.begin(), end = tokens.end();
  53. // int kkkk = 0;
  54. while(i != end)
  55. {
  56. // kkkk ++;
  57. token = (*i);
  58. switch(state)
  59. {
  60. case READY:
  61. if(token->type == TID_WORD)
  62. {
  63. if(token->lexeme == "import")
  64. {
  65. node = new (std::nothrow) PUConcreteNode;
  66. node->token = token->lexeme;
  67. node->file = token->file;
  68. node->line = token->line;
  69. node->type = CNT_IMPORT;
  70. // The next token is the target
  71. ++i;
  72. if(i == end || ((*i)->type != TID_WORD && (*i)->type != TID_QUOTE))
  73. {
  74. printf("Except,expected import target at line :%d,ScriptParser::parse",node->line);
  75. }
  76. PUConcreteNode* temp = new (std::nothrow) PUConcreteNode;
  77. temp->parent = node;
  78. temp->file = (*i)->file;
  79. temp->line = (*i)->line;
  80. temp->type = (*i)->type == TID_WORD ? CNT_WORD : CNT_QUOTE;
  81. if(temp->type == CNT_QUOTE)
  82. temp->token = (*i)->lexeme.substr(1, token->lexeme.size() - 2);
  83. else
  84. temp->token = (*i)->lexeme;
  85. node->children.push_back(temp);
  86. // The second-next token is the source
  87. ++i;
  88. ++i;
  89. if(i == end || ((*i)->type != TID_WORD && (*i)->type != TID_QUOTE))
  90. {
  91. printf("expected import source at line :%d,ScriptParser::parse",node->line);
  92. }
  93. temp = new (std::nothrow) PUConcreteNode;
  94. temp->parent = node;
  95. temp->file = (*i)->file;
  96. temp->line = (*i)->line;
  97. temp->type = (*i)->type == TID_WORD ? CNT_WORD : CNT_QUOTE;
  98. if(temp->type == CNT_QUOTE)
  99. temp->token = (*i)->lexeme.substr(1, (*i)->lexeme.size() - 2);
  100. else
  101. temp->token = (*i)->lexeme;
  102. node->children.push_back(temp);
  103. // Consume all the newlines
  104. i = skipNewlines(i, end);
  105. // Insert the node
  106. if(parent)
  107. {
  108. node->parent = parent;
  109. parent->children.push_back(node);
  110. }
  111. else
  112. {
  113. node->parent = 0;
  114. nodes.push_back(node);
  115. }
  116. node = nullptr;
  117. }
  118. else if(token->lexeme == "set")
  119. {
  120. node = new (std::nothrow) PUConcreteNode;
  121. node->token = token->lexeme;
  122. node->file = token->file;
  123. node->line = token->line;
  124. node->type = CNT_VARIABLE_ASSIGN;
  125. // The next token is the variable
  126. ++i;
  127. if(i == end || (*i)->type != TID_VARIABLE)
  128. {
  129. printf("Exception");
  130. }
  131. PUConcreteNode* temp = new (std::nothrow) PUConcreteNode;
  132. temp->parent = node;
  133. temp->file = (*i)->file;
  134. temp->line = (*i)->line;
  135. temp->type = CNT_VARIABLE;
  136. temp->token = (*i)->lexeme;
  137. node->children.push_back(temp);
  138. // The next token is the assignment
  139. ++i;
  140. if(i == end || ((*i)->type != TID_WORD && (*i)->type != TID_QUOTE))
  141. {
  142. printf("expected variable value at line %d ScriptParser::parse\n",node->line);
  143. }
  144. temp = new (std::nothrow) PUConcreteNode;
  145. temp->parent = node;
  146. temp->file = (*i)->file;
  147. temp->line = (*i)->line;
  148. temp->type = (*i)->type == TID_WORD ? CNT_WORD : CNT_QUOTE;
  149. if(temp->type == CNT_QUOTE)
  150. temp->token = (*i)->lexeme.substr(1, (*i)->lexeme.size() - 2);
  151. else
  152. temp->token = (*i)->lexeme;
  153. node->children.push_back(temp);
  154. // Consume all the newlines
  155. i = skipNewlines(i, end);
  156. // Insert the node
  157. if(parent)
  158. {
  159. node->parent = parent;
  160. parent->children.push_back(node);
  161. }
  162. else
  163. {
  164. node->parent = 0;
  165. nodes.push_back(node);
  166. }
  167. node = nullptr;
  168. }
  169. else
  170. {
  171. node = new (std::nothrow) PUConcreteNode();
  172. node->file = token->file;
  173. node->line = token->line;
  174. node->type = token->type == TID_WORD ? CNT_WORD : CNT_QUOTE;
  175. if(node->type == CNT_QUOTE)
  176. node->token = token->lexeme.substr(1, token->lexeme.size() - 2);
  177. else
  178. node->token = token->lexeme;
  179. // Insert the node
  180. if(parent)
  181. {
  182. node->parent = parent;
  183. parent->children.push_back(node);
  184. }
  185. else
  186. {
  187. node->parent = 0;
  188. nodes.push_back(node);
  189. }
  190. // Set the parent
  191. parent = node;
  192. // Switch states
  193. state = OBJECT;
  194. node = nullptr;
  195. }
  196. }
  197. else if(token->type == TID_RBRACKET)
  198. {
  199. // Go up one level if we can
  200. if(parent)
  201. parent = parent->parent;
  202. node = new (std::nothrow) PUConcreteNode();
  203. node->token = token->lexeme;
  204. node->file = token->file;
  205. node->line = token->line;
  206. node->type = CNT_RBRACE;
  207. // Consume all the newlines
  208. i = skipNewlines(i, end);
  209. // Insert the node
  210. if(parent)
  211. {
  212. node->parent = parent;
  213. parent->children.push_back(node);
  214. }
  215. else
  216. {
  217. node->parent = 0;
  218. nodes.push_back(node);
  219. }
  220. // Move up another level
  221. if(parent)
  222. parent = parent->parent;
  223. node = nullptr;
  224. }
  225. break;
  226. case OBJECT:
  227. if(token->type == TID_NEWLINE)
  228. {
  229. // Look ahead to the next non-newline token and if it isn't an {, this was a property
  230. PUScriptTokenList::const_iterator next = skipNewlines(i, end);
  231. if(next == end || (*next)->type != TID_LBRACKET)
  232. {
  233. // Ended a property here
  234. if(parent)
  235. parent = parent->parent;
  236. state = READY;
  237. }
  238. }
  239. else if(token->type == TID_COLON)
  240. {
  241. node = new (std::nothrow) PUConcreteNode();
  242. node->token = token->lexeme;
  243. node->file = token->file;
  244. node->line = token->line;
  245. node->type = CNT_COLON;
  246. // The following token are the parent objects (base classes).
  247. // Require at least one of them.
  248. PUScriptTokenList::const_iterator j = i + 1;
  249. j = skipNewlines(j, end);
  250. if(j == end || ((*j)->type != TID_WORD && (*j)->type != TID_QUOTE)) {
  251. printf("expected object identifier at line %d ScriptParser::parse\n",node->line);
  252. }
  253. while(j != end && ((*j)->type == TID_WORD || (*j)->type == TID_QUOTE))
  254. {
  255. PUConcreteNode* tempNode = new (std::nothrow) PUConcreteNode;
  256. tempNode->token = (*j)->lexeme;
  257. tempNode->file = (*j)->file;
  258. tempNode->line = (*j)->line;
  259. tempNode->type = (*j)->type == TID_WORD ? CNT_WORD : CNT_QUOTE;
  260. tempNode->parent = node;
  261. node->children.push_back(tempNode);
  262. ++j;
  263. }
  264. // Move it backwards once, since the end of the loop moves it forwards again anyway
  265. --j;
  266. i = j;
  267. // Insert the node
  268. if(parent)
  269. {
  270. node->parent = parent;
  271. parent->children.push_back(node);
  272. }
  273. else
  274. {
  275. node->parent = 0;
  276. nodes.push_back(node);
  277. }
  278. node = nullptr;
  279. }
  280. else if(token->type == TID_LBRACKET)
  281. {
  282. node = new (std::nothrow) PUConcreteNode;
  283. node->token = token->lexeme;
  284. node->file = token->file;
  285. node->line = token->line;
  286. node->type = CNT_LBRACE;
  287. // Consume all the newlines
  288. i = skipNewlines(i, end);
  289. // Insert the node
  290. if(parent)
  291. {
  292. node->parent = parent;
  293. parent->children.push_back(node);
  294. }
  295. else
  296. {
  297. node->parent = 0;
  298. nodes.push_back(node);
  299. }
  300. // Set the parent
  301. parent = node;
  302. // Change the state
  303. state = READY;
  304. node = nullptr;
  305. }
  306. else if(token->type == TID_RBRACKET)
  307. {
  308. // Go up one level if we can
  309. if(parent)
  310. parent = parent->parent;
  311. // If the parent is currently a { then go up again
  312. if(parent && parent->type == CNT_LBRACE && parent->parent)
  313. parent = parent->parent;
  314. node = new (std::nothrow) PUConcreteNode;
  315. node->token = token->lexeme;
  316. node->file = token->file;
  317. node->line = token->line;
  318. node->type = CNT_RBRACE;
  319. // Consume all the newlines
  320. i = skipNewlines(i, end);
  321. // Insert the node
  322. if(parent)
  323. {
  324. node->parent = parent;
  325. parent->children.push_back(node);
  326. }
  327. else
  328. {
  329. node->parent = 0;
  330. nodes.push_back(node);
  331. }
  332. // Move up another level
  333. if(parent)
  334. parent = parent->parent;
  335. node = nullptr;
  336. state = READY;
  337. }
  338. else if(token->type == TID_VARIABLE)
  339. {
  340. node = new (std::nothrow) PUConcreteNode;
  341. node->token = token->lexeme;
  342. node->file = token->file;
  343. node->line = token->line;
  344. node->type = CNT_VARIABLE;
  345. // Insert the node
  346. if(parent)
  347. {
  348. node->parent = parent;
  349. parent->children.push_back(node);
  350. }
  351. else
  352. {
  353. node->parent = 0;
  354. nodes.push_back(node);
  355. }
  356. node = nullptr;
  357. }
  358. else if(token->type == TID_QUOTE)
  359. {
  360. node = new (std::nothrow) PUConcreteNode;
  361. node->token = token->lexeme.substr(1, token->lexeme.size() - 2);
  362. node->file = token->file;
  363. node->line = token->line;
  364. node->type = CNT_QUOTE;
  365. // Insert the node
  366. if(parent)
  367. {
  368. node->parent = parent;
  369. parent->children.push_back(node);
  370. }
  371. else
  372. {
  373. node->parent = 0;
  374. nodes.push_back(node);
  375. }
  376. node = nullptr;
  377. }
  378. else if(token->type == TID_WORD)
  379. {
  380. node = new (std::nothrow) PUConcreteNode;
  381. node->token = token->lexeme;
  382. node->file = token->file;
  383. node->line = token->line;
  384. node->type = CNT_WORD;
  385. // Insert the node
  386. if(parent)
  387. {
  388. node->parent = parent;
  389. parent->children.push_back(node);
  390. }
  391. else
  392. {
  393. node->parent = 0;
  394. nodes.push_back(node);
  395. }
  396. node = nullptr;
  397. }
  398. break;
  399. }
  400. ++i;
  401. }
  402. // traceScriptParser(nodes);//
  403. // printf("kkkk:%d\n",kkkk);//
  404. }
  405. void PUScriptParser::parseChunk(PUConcreteNodeList& nodes, const PUScriptTokenList &tokens)
  406. {
  407. PUConcreteNode* node = nullptr;
  408. PUScriptToken *token = 0;
  409. for(PUScriptTokenList::const_iterator i = tokens.begin(); i != tokens.end(); ++i)
  410. {
  411. token = *i;
  412. node = nullptr;
  413. switch(token->type)
  414. {
  415. case TID_VARIABLE:
  416. node = new (std::nothrow) PUConcreteNode;
  417. node->file = token->file;
  418. node->line = token->line;
  419. node->parent = 0;
  420. node->token = token->lexeme;
  421. node->type = CNT_VARIABLE;
  422. break;
  423. case TID_WORD:
  424. node = new (std::nothrow) PUConcreteNode;
  425. node->file = token->file;
  426. node->line = token->line;
  427. node->parent = 0;
  428. node->token = token->lexeme;
  429. node->type = CNT_WORD;
  430. break;
  431. case TID_QUOTE:
  432. node = new (std::nothrow) PUConcreteNode;
  433. node->file = token->file;
  434. node->line = token->line;
  435. node->parent = 0;
  436. node->token = token->lexeme.substr(1, token->lexeme.size() - 2);
  437. node->type = CNT_QUOTE;
  438. default:
  439. printf("unexpected token,%s,%d\n",token->lexeme.c_str(),token->line);
  440. }
  441. if(node != nullptr)
  442. nodes.push_back(node);
  443. }
  444. }
  445. PUScriptToken *PUScriptParser::getToken(PUScriptTokenList::iterator i, PUScriptTokenList::iterator end, int offset)
  446. {
  447. PUScriptToken *token = 0;
  448. PUScriptTokenList::iterator iter = i + offset;
  449. if(iter != end)
  450. token = (*i);
  451. return token;
  452. }
  453. PUScriptTokenList::const_iterator PUScriptParser::skipNewlines(PUScriptTokenList::const_iterator i, PUScriptTokenList::const_iterator end)
  454. {
  455. while(i != end && (*i)->type == TID_NEWLINE)
  456. ++i;
  457. return i;
  458. }
  459. PUConcreteNode::~PUConcreteNode()
  460. {
  461. for (auto iter : children){
  462. delete iter;
  463. }
  464. }
  465. NS_CC_END