Ogre原始碼淺析——指令碼及其解析(三)
阿新 • • 發佈:2019-01-10
1 ConcreteNodeListPtr ScriptParser::parse(const ScriptTokenListPtr &tokens) 2 { 3 // MEMCATEGORY_GENERAL because SharedPtr can only free using that category 4 ConcreteNodeListPtr nodes(OGRE_NEW_T(ConcreteNodeList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T); 5 6 enum{READY, OBJECT}; 7 uint32 state = READY; 8 9 ConcreteNode *parent = 0; 10 ConcreteNodePtr node; 11 ScriptToken *token = 0; 12 ScriptTokenList::iterator i = tokens->begin(), end = tokens->end(); 13 while(i != end) 14 { 15 token = (*i).get(); 16 17 switch(state) 18 { 19 case READY: 20 if(token->type == TID_WORD) 21 { 22 if(token->lexeme == "import") 23 { 24 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 25 node->token = token->lexeme; 26 node->file = token->file; 27 node->line = token->line; 28 node->type = CNT_IMPORT; 29 30 // The next token is the target 31 ++i; 32 if(i == end || ((*i)->type != TID_WORD && (*i)->type != TID_QUOTE)) 33 OGRE_EXCEPT(Exception::ERR_INVALID_STATE, 34 Ogre::String("expected import target at line ") + 35 Ogre::StringConverter::toString(node->line), 36 "ScriptParser::parse"); 37 ConcreteNodePtr temp(OGRE_NEW ConcreteNode()); 38 temp->parent = node.get(); 39 temp->file = (*i)->file; 40 temp->line = (*i)->line; 41 temp->type = (*i)->type == TID_WORD ? CNT_WORD : CNT_QUOTE; 42 if(temp->type == CNT_QUOTE) 43 temp->token = (*i)->lexeme.substr(1, token->lexeme.size() - 2); 44 else 45 temp->token = (*i)->lexeme; 46 node->children.push_back(temp); 47 48 // The second-next token is the source 49 ++i; 50 ++i; 51 if(i == end || ((*i)->type != TID_WORD && (*i)->type != TID_QUOTE)) 52 OGRE_EXCEPT(Exception::ERR_INVALID_STATE, 53 Ogre::String("expected import source at line ") + 54 Ogre::StringConverter::toString(node->line), 55 "ScriptParser::parse"); 56 temp = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 57 temp->parent = node.get(); 58 temp->file = (*i)->file; 59 temp->line = (*i)->line; 60 temp->type = (*i)->type == TID_WORD ? CNT_WORD : CNT_QUOTE; 61 if(temp->type == CNT_QUOTE) 62 temp->token = (*i)->lexeme.substr(1, (*i)->lexeme.size() - 2); 63 else 64 temp->token = (*i)->lexeme; 65 node->children.push_back(temp); 66 67 // Consume all the newlines 68 i = skipNewlines(i, end); 69 70 // Insert the node 71 if(parent) 72 { 73 node->parent = parent; 74 parent->children.push_back(node); 75 } 76 else 77 { 78 node->parent = 0; 79 nodes->push_back(node); 80 } 81 node = ConcreteNodePtr(); 82 } 83 else if(token->lexeme == "set") 84 { 85 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 86 node->token = token->lexeme; 87 node->file = token->file; 88 node->line = token->line; 89 node->type = CNT_VARIABLE_ASSIGN; 90 91 // The next token is the variable 92 ++i; 93 if(i == end || (*i)->type != TID_VARIABLE) 94 OGRE_EXCEPT(Exception::ERR_INVALID_STATE, 95 Ogre::String("expected variable name at line ") + 96 Ogre::StringConverter::toString(node->line), 97 "ScriptParser::parse"); 98 ConcreteNodePtr temp(OGRE_NEW ConcreteNode()); 99 temp->parent = node.get(); 100 temp->file = (*i)->file; 101 temp->line = (*i)->line; 102 temp->type = CNT_VARIABLE; 103 temp->token = (*i)->lexeme; 104 node->children.push_back(temp); 105 106 // The next token is the assignment 107 ++i; 108 if(i == end || ((*i)->type != TID_WORD && (*i)->type != TID_QUOTE)) 109 OGRE_EXCEPT(Exception::ERR_INVALID_STATE, 110 Ogre::String("expected variable value at line ") + 111 Ogre::StringConverter::toString(node->line), 112 "ScriptParser::parse"); 113 temp = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 114 temp->parent = node.get(); 115 temp->file = (*i)->file; 116 temp->line = (*i)->line; 117 temp->type = (*i)->type == TID_WORD ? CNT_WORD : CNT_QUOTE; 118 if(temp->type == CNT_QUOTE) 119 temp->token = (*i)->lexeme.substr(1, (*i)->lexeme.size() - 2); 120 else 121 temp->token = (*i)->lexeme; 122 node->children.push_back(temp); 123 124 // Consume all the newlines 125 i = skipNewlines(i, end); 126 127 // Insert the node 128 if(parent) 129 { 130 node->parent = parent; 131 parent->children.push_back(node); 132 } 133 else 134 { 135 node->parent = 0; 136 nodes->push_back(node); 137 } 138 node = ConcreteNodePtr(); 139 } 140 else 141 { 142 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 143 node->file = token->file; 144 node->line = token->line; 145 node->type = token->type == TID_WORD ? CNT_WORD : CNT_QUOTE; 146 if(node->type == CNT_QUOTE) 147 node->token = token->lexeme.substr(1, token->lexeme.size() - 2); 148 else 149 node->token = token->lexeme; 150 151 // Insert the node 152 if(parent) 153 { 154 node->parent = parent; 155 parent->children.push_back(node); 156 } 157 else 158 { 159 node->parent = 0; 160 nodes->push_back(node); 161 } 162 163 // Set the parent 164 parent = node.get(); 165 166 // Switch states 167 state = OBJECT; 168 169 node = ConcreteNodePtr(); 170 } 171 } 172 else if(token->type == TID_RBRACKET) 173 { 174 // Go up one level if we can 175 if(parent) 176 parent = parent->parent; 177 178 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 179 node->token = token->lexeme; 180 node->file = token->file; 181 node->line = token->line; 182 node->type = CNT_RBRACE; 183 184 // Consume all the newlines 185 i = skipNewlines(i, end); 186 187 // Insert the node 188 if(parent) 189 { 190 node->parent = parent; 191 parent->children.push_back(node); 192 } 193 else 194 { 195 node->parent = 0; 196 nodes->push_back(node); 197 } 198 199 // Move up another level 200 if(parent) 201 parent = parent->parent; 202 203 node = ConcreteNodePtr(); 204 } 205 break; 206 case OBJECT: 207 if(token->type == TID_NEWLINE) 208 { 209 // Look ahead to the next non-newline token and if it isn't an {, this was a property 210 ScriptTokenList::iterator next = skipNewlines(i, end); 211 if(next == end || (*next)->type != TID_LBRACKET) 212 { 213 // Ended a property here 214 if(parent) 215 parent = parent->parent; 216 state = READY; 217 } 218 } 219 else if(token->type == TID_COLON) 220 { 221 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 222 node->token = token->lexeme; 223 node->file = token->file; 224 node->line = token->line; 225 node->type = CNT_COLON; 226 227 // The following token are the parent objects (base classes). 228 // Require at least one of them. 229 230 ScriptTokenList::iterator j = i + 1; 231 j = skipNewlines(j, end); 232 if(j == end || ((*j)->type != TID_WORD && (*j)->type != TID_QUOTE)) { 233 OGRE_EXCEPT(Exception::ERR_INVALID_STATE, 234 Ogre::String("expected object identifier at line ") + 235 Ogre::StringConverter::toString(node->line), 236 "ScriptParser::parse"); 237 } 238 239 while(j != end && ((*j)->type == TID_WORD || (*j)->type == TID_QUOTE)) 240 { 241 ConcreteNodePtr tempNode = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 242 tempNode->token = (*j)->lexeme; 243 tempNode->file = (*j)->file; 244 tempNode->line = (*j)->line; 245 tempNode->type = (*j)->type == TID_WORD ? CNT_WORD : CNT_QUOTE; 246 tempNode->parent = node.get(); 247 node->children.push_back(tempNode); 248 ++j; 249 } 250 251 // Move it backwards once, since the end of the loop moves it forwards again anyway 252 j--; 253 i = j; 254 255 // Insert the node 256 if(parent) 257 { 258 node->parent = parent; 259 parent->children.push_back(node); 260 } 261 else 262 { 263 node->parent = 0; 264 nodes->push_back(node); 265 } 266 node = ConcreteNodePtr(); 267 } 268 else if(token->type == TID_LBRACKET) 269 { 270 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 271 node->token = token->lexeme; 272 node->file = token->file; 273 node->line = token->line; 274 node->type = CNT_LBRACE; 275 276 // Consume all the newlines 277 i = skipNewlines(i, end); 278 279 // Insert the node 280 if(parent) 281 { 282 node->parent = parent; 283 parent->children.push_back(node); 284 } 285 else 286 { 287 node->parent = 0; 288 nodes->push_back(node); 289 } 290 291 // Set the parent 292 parent = node.get(); 293 294 // Change the state 295 state = READY; 296 297 node = ConcreteNodePtr(); 298 } 299 else if(token->type == TID_RBRACKET) 300 { 301 // Go up one level if we can 302 if(parent) 303 parent = parent->parent; 304 305 // If the parent is currently a { then go up again 306 if(parent && parent->type == CNT_LBRACE && parent->parent) 307 parent = parent->parent; 308 309 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 310 node->token = token->lexeme; 311 node->file = token->file; 312 node->line = token->line; 313 node->type = CNT_RBRACE; 314 315 // Consume all the newlines 316 i = skipNewlines(i, end); 317 318 // Insert the node 319 if(parent) 320 { 321 node->parent = parent; 322 parent->children.push_back(node); 323 } 324 else 325 { 326 node->parent = 0; 327 nodes->push_back(node); 328 } 329 330 // Move up another level 331 if(parent) 332 parent = parent->parent; 333 334 node = ConcreteNodePtr(); 335 state = READY; 336 } 337 else if(token->type == TID_VARIABLE) 338 { 339 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 340 node->token = token->lexeme; 341 node->file = token->file; 342 node->line = token->line; 343 node->type = CNT_VARIABLE; 344 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 = ConcreteNodePtr(); 357 } 358 else if(token->type == TID_QUOTE) 359 { 360 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 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 366 // Insert the node 367 if(parent) 368 { 369 node->parent = parent; 370 parent->children.push_back(node); 371 } 372 else 373 { 374 node->parent = 0; 375 nodes->push_back(node); 376 } 377 node = ConcreteNodePtr(); 378 } 379 else if(token->type == TID_WORD) 380 { 381 node = ConcreteNodePtr(OGRE_NEW ConcreteNode()); 382 node->token = token->lexeme; 383 node->file = token->file; 384 node->line = token->line; 385 node->type = CNT_WORD; 386 387 // Insert the node 388 if(parent) 389 { 390 node->parent = parent; 391 parent->children.push_back(node); 392 } 393 else 394 { 395 node->parent = 0; 396 nodes->push_back(node); 397 } 398 node = ConcreteNodePtr(); 399 } 400 break; 401 } 402 403 ++i; 404 } 405 406 return nodes; 407 }