parser.cxx

changeset 50
2e333a3ca49a
parent 49
8e2f7a031410
child 51
2cfa6edbf928
equal deleted inserted replaced
49:8e2f7a031410 50:2e333a3ca49a
68 68
69 // ============================================================================ 69 // ============================================================================
70 // Main parser code. Begins read of the script file, checks the syntax of it 70 // Main parser code. Begins read of the script file, checks the syntax of it
71 // and writes the data to the object file via ObjWriter - which also takes care 71 // and writes the data to the object file via ObjWriter - which also takes care
72 // of necessary buffering so stuff is written in the correct order. 72 // of necessary buffering so stuff is written in the correct order.
73 void ScriptReader::BeginParse (ObjWriter* w) { 73 void ScriptReader::ParseBotScript (ObjWriter* w) {
74 while (Next()) { 74 while (Next()) {
75 // ============================================================ 75 // ============================================================
76 if (!token.icompare ("state")) { 76 if (!token.compare ("state")) {
77 MUST_TOPLEVEL 77 MUST_TOPLEVEL
78 78
79 MustString (); 79 MustString ();
80 80
81 // State name must be a word. 81 // State name must be a word.
106 g_GotMainLoop = false; 106 g_GotMainLoop = false;
107 continue; 107 continue;
108 } 108 }
109 109
110 // ============================================================ 110 // ============================================================
111 if (!token.icompare ("event")) { 111 if (!token.compare ("event")) {
112 MUST_TOPLEVEL 112 MUST_TOPLEVEL
113 113
114 // Event definition 114 // Event definition
115 MustString (); 115 MustString ();
116 116
127 g_NumEvents++; 127 g_NumEvents++;
128 continue; 128 continue;
129 } 129 }
130 130
131 // ============================================================ 131 // ============================================================
132 if (!token.icompare ("mainloop")) { 132 if (!token.compare ("mainloop")) {
133 MUST_TOPLEVEL 133 MUST_TOPLEVEL
134 MustNext ("{"); 134 MustNext ("{");
135 135
136 // Mode must be set before dataheader is written here! 136 // Mode must be set before dataheader is written here!
137 g_CurMode = MODE_MAINLOOP; 137 g_CurMode = MODE_MAINLOOP;
138 w->Write (DH_MAINLOOP); 138 w->Write (DH_MAINLOOP);
139 continue; 139 continue;
140 } 140 }
141 141
142 // ============================================================ 142 // ============================================================
143 if (!token.icompare ("onenter") || !token.icompare ("onexit")) { 143 if (!token.compare ("onenter") || !token.compare ("onexit")) {
144 MUST_TOPLEVEL 144 MUST_TOPLEVEL
145 bool onenter = !token.compare ("onenter"); 145 bool onenter = !token.compare ("onenter");
146 MustNext ("{"); 146 MustNext ("{");
147 147
148 // Mode must be set before dataheader is written here, 148 // Mode must be set before dataheader is written here,
174 MustNext (";"); 174 MustNext (";");
175 continue; 175 continue;
176 } 176 }
177 177
178 // ============================================================ 178 // ============================================================
179 // Label
180 if (!PeekNext().compare (":")) {
181 MUST_NOT_TOPLEVEL
182
183 if (IsKeyword (token))
184 ParserError ("label name `%s` conflicts with keyword\n", token.chars());
185 if (FindCommand (token))
186 ParserError ("label name `%s` conflicts with command name\n", token.chars());
187 if (FindGlobalVariable (token))
188 ParserError ("label name `%s` conflicts with variable\n", token.chars());
189
190 w->AddMark (token);
191 MustNext (":");
192 continue;
193 }
194
195 // ============================================================
196 // Goto 179 // Goto
197 if (!token.icompare ("goto")) { 180 if (!token.compare ("goto")) {
198 MUST_NOT_TOPLEVEL 181 MUST_NOT_TOPLEVEL
199 182
200 // Get the name of the label 183 // Get the name of the label
201 MustNext (); 184 MustNext ();
202 185
214 continue; 197 continue;
215 } 198 }
216 199
217 // ============================================================ 200 // ============================================================
218 // If 201 // If
219 if (!token.icompare ("if")) { 202 if (!token.compare ("if")) {
220 MUST_NOT_TOPLEVEL 203 MUST_NOT_TOPLEVEL
221 PushBlockStack (); 204 PushBlockStack ();
222 205
223 // Condition 206 // Condition
224 MustNext ("("); 207 MustNext ("(");
264 // Condition 247 // Condition
265 MustNext ("("); 248 MustNext ("(");
266 MustNext (); 249 MustNext ();
267 DataBuffer* expr = ParseExpression (TYPE_INT); 250 DataBuffer* expr = ParseExpression (TYPE_INT);
268 MustNext (")"); 251 MustNext (")");
269
270 MustNext ("{"); 252 MustNext ("{");
271 253
272 // Write condition 254 // Write condition
273 w->WriteBuffer (expr); 255 w->WriteBuffer (expr);
274 256
283 continue; 265 continue;
284 } 266 }
285 267
286 // ============================================================ 268 // ============================================================
287 // For loop 269 // For loop
288 if (!token.icompare ("for")) { 270 if (!token.compare ("for")) {
289 MUST_NOT_TOPLEVEL 271 MUST_NOT_TOPLEVEL
290 PushBlockStack (); 272 PushBlockStack ();
291 273
292 // Initializer 274 // Initializer
293 MustNext ("("); 275 MustNext ("(");
326 continue; 308 continue;
327 } 309 }
328 310
329 // ============================================================ 311 // ============================================================
330 // Do/while loop 312 // Do/while loop
331 if (!token.icompare ("do")) { 313 if (!token.compare ("do")) {
332 MUST_NOT_TOPLEVEL 314 MUST_NOT_TOPLEVEL
333 PushBlockStack (); 315 PushBlockStack ();
334 MustNext ("{"); 316 MustNext ("{");
335 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); 317 blockstack[g_BlockStackCursor].mark1 = w->AddMark ("");
336 blockstack[g_BlockStackCursor].type = BLOCKTYPE_DO; 318 blockstack[g_BlockStackCursor].type = BLOCKTYPE_DO;
337 continue; 319 continue;
338 } 320 }
339 321
340 // ============================================================ 322 // ============================================================
341 // Switch 323 // Switch
342 if (!token.icompare ("switch")) { 324 if (!token.compare ("switch")) {
343 /* This goes a bit tricky. switch is structured in the 325 /* This goes a bit tricky. switch is structured in the
344 * bytecode followingly: 326 * bytecode followingly:
345 * (expression) 327 * (expression)
346 * case a: goto casemark1 328 * case a: goto casemark1
347 * case b: goto casemark2 329 * case b: goto casemark2
360 w->WriteBuffer (ParseExpression (TYPE_INT)); 342 w->WriteBuffer (ParseExpression (TYPE_INT));
361 MustNext (")"); 343 MustNext (")");
362 MustNext ("{"); 344 MustNext ("{");
363 blockstack[g_BlockStackCursor].type = BLOCKTYPE_SWITCH; 345 blockstack[g_BlockStackCursor].type = BLOCKTYPE_SWITCH;
364 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); // end mark 346 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); // end mark
365 continue; 347 blockstack[g_BlockStackCursor].buffer1 = NULL; // default header
366 } 348 continue;
367 349 }
368 // ============================================================ 350
369 if (!token.icompare ("case")) { 351 // ============================================================
352 if (!token.compare ("case")) {
370 // case is only allowed inside switch 353 // case is only allowed inside switch
371 if (g_BlockStackCursor <= 0 || blockstack[g_BlockStackCursor].type != BLOCKTYPE_SWITCH)
372 ParserError ("`case` outside switch");
373
374 BlockInformation* info = &blockstack[g_BlockStackCursor]; 354 BlockInformation* info = &blockstack[g_BlockStackCursor];
375 info->casecursor++; 355 if (info->type != BLOCKTYPE_SWITCH)
376 if (info->casecursor >= MAX_CASE) 356 ParserError ("case label outside switch");
377 ParserError ("too many `case` statements in one switch");
378 357
379 // Get the literal (Zandronum does not support expressions here) 358 // Get the literal (Zandronum does not support expressions here)
380 MustNumber (); 359 MustNumber ();
381 int num = atoi (token.chars ()); 360 int num = atoi (token.chars ());
382
383 MustNext (":"); 361 MustNext (":");
384 362
385 // Init a mark for the case buffer 363 for (int i = 0; i < MAX_CASE; i++)
386 int m = w->AddMark (""); 364 if (info->casenumbers[i] == num)
387 info->casemarks[info->casecursor] = m; 365 ParserError ("multiple case %d labels in one switch", num);
388 366
389 // Write down the expression and case-go-to. This builds 367 // Write down the expression and case-go-to. This builds
390 // the case tree. The closing event will write the actual 368 // the case tree. The closing event will write the actual
391 // blocks and move the marks appropriately. 369 // blocks and move the marks appropriately.
392 // 370 // AddSwitchCase will add the reference to the mark
393 // NULL the switch buffer for the case-go-to statement, 371 // for the case block that this heralds, and takes care
372 // of buffering setup and stuff like that.
373 // NULL the switch buffer for the case-go-to statement,
394 // we want it all under the switch, not into the case-buffers. 374 // we want it all under the switch, not into the case-buffers.
395 w->SwitchBuffer = NULL; 375 w->SwitchBuffer = NULL;
396 w->Write<word> (DH_CASEGOTO); 376 w->Write<word> (DH_CASEGOTO);
397 w->Write<word> (num); 377 w->Write<word> (num);
398 w->AddReference (m); 378 AddSwitchCase (w, NULL);
399 379 info->casenumbers[info->casecursor] = num;
400 // Init a buffer for the case block, tell the object 380 continue;
401 // writer to record all written data to it. 381 }
402 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer; 382
383 if (!token.compare ("default")) {
384 BlockInformation* info = &blockstack[g_BlockStackCursor];
385 if (info->type != BLOCKTYPE_SWITCH)
386 ParserError ("default label outside switch");
387
388 if (info->buffer1)
389 ParserError ("multiple default labels in one switch");
390
391 MustNext (":");
392
393 // The default header is buffered into buffer1, since
394 // it has to be the last of the case headers
395 //
396 // Since the expression is pushed into the switch
397 // and is only popped when case succeeds, we have
398 // to pop it with DH_DROP manually if we end up in
399 // a default.
400 DataBuffer* b = new DataBuffer;
401 info->buffer1 = b;
402 b->Write<word> (DH_DROP);
403 b->Write<word> (DH_GOTO);
404 AddSwitchCase (w, b);
403 continue; 405 continue;
404 } 406 }
405 407
406 // ============================================================ 408 // ============================================================
407 // Break statement. 409 // Break statement.
408 if (!token.icompare ("break")) { 410 if (!token.compare ("break")) {
409 if (!g_BlockStackCursor) 411 if (!g_BlockStackCursor)
410 ParserError ("unexpected `break`"); 412 ParserError ("unexpected `break`");
411 413
412 BlockInformation* info = &blockstack[g_BlockStackCursor]; 414 BlockInformation* info = &blockstack[g_BlockStackCursor];
413 415
428 ParserError ("unexpected `break`"); 430 ParserError ("unexpected `break`");
429 break; 431 break;
430 } 432 }
431 433
432 MustNext (";"); 434 MustNext (";");
435 continue;
436 }
437
438 // ============================================================
439 // Label
440 if (!PeekNext().compare (":")) {
441 MUST_NOT_TOPLEVEL
442
443 if (IsKeyword (token))
444 ParserError ("label name `%s` conflicts with keyword\n", token.chars());
445 if (FindCommand (token))
446 ParserError ("label name `%s` conflicts with command name\n", token.chars());
447 if (FindGlobalVariable (token))
448 ParserError ("label name `%s` conflicts with variable\n", token.chars());
449
450 w->AddMark (token);
451 MustNext (":");
433 continue; 452 continue;
434 } 453 }
435 454
436 // ============================================================ 455 // ============================================================
437 if (!token.compare ("}")) { 456 if (!token.compare ("}")) {
469 w->WriteBuffer (expr); 488 w->WriteBuffer (expr);
470 w->Write<long> (DH_IFGOTO); 489 w->Write<long> (DH_IFGOTO);
471 w->AddReference (info->mark1); 490 w->AddReference (info->mark1);
472 break; 491 break;
473 } 492 }
474
475 case BLOCKTYPE_SWITCH: { 493 case BLOCKTYPE_SWITCH: {
476 // Switch closes. Move down to the record buffer of 494 // Switch closes. Move down to the record buffer of
477 // the lower block. 495 // the lower block.
478 BlockInformation* previnfo = &blockstack[g_BlockStackCursor - 1]; 496 BlockInformation* previnfo = &blockstack[g_BlockStackCursor - 1];
479 if (previnfo->casecursor != -1) 497 if (previnfo->casecursor != -1)
480 w->SwitchBuffer = previnfo->casebuffers[previnfo->casecursor]; 498 w->SwitchBuffer = previnfo->casebuffers[previnfo->casecursor];
481 else 499 else
482 w->SwitchBuffer = NULL; 500 w->SwitchBuffer = NULL;
501
502 // If there was a default in the switch, write its header down now.
503 // If not, write instruction to jump to the end of switch after
504 // the headers (thus won't fall-through if no case matched)
505 if (info->buffer1)
506 w->WriteBuffer (info->buffer1);
507 else {
508 w->Write<word> (DH_DROP);
509 w->Write<word> (DH_GOTO);
510 w->AddReference (info->mark1);
511 }
483 512
484 // Go through all of the buffers we 513 // Go through all of the buffers we
485 // recorded down and write them. 514 // recorded down and write them.
486 for (unsigned int u = 0; u < MAX_CASE; u++) { 515 for (unsigned int u = 0; u < MAX_CASE; u++) {
487 if (!info->casebuffers[u]) 516 if (!info->casebuffers[u])
819 info->buffer1 = NULL; 848 info->buffer1 = NULL;
820 info->casecursor = -1; 849 info->casecursor = -1;
821 for (int i = 0; i < MAX_CASE; i++) { 850 for (int i = 0; i < MAX_CASE; i++) {
822 info->casemarks[i] = MAX_MARKS; 851 info->casemarks[i] = MAX_MARKS;
823 info->casebuffers[i] = NULL; 852 info->casebuffers[i] = NULL;
853 info->casenumbers[i] = -1;
824 } 854 }
825 } 855 }
826 856
827 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) { 857 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) {
828 // If it's a variable, expect assignment. 858 // If it's a variable, expect assignment.
833 863
834 // If it's not a keyword, parse it as an expression. 864 // If it's not a keyword, parse it as an expression.
835 DataBuffer* b = ParseExpression (TYPE_VOID); 865 DataBuffer* b = ParseExpression (TYPE_VOID);
836 return b; 866 return b;
837 } 867 }
868
869 void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) {
870 BlockInformation* info = &blockstack[g_BlockStackCursor];
871
872 info->casecursor++;
873 if (info->casecursor >= MAX_CASE)
874 ParserError ("too many cases in one switch");
875
876 // Init a mark for the case buffer
877 int m = w->AddMark ("");
878 info->casemarks[info->casecursor] = m;
879
880 // Add a reference to the mark. "case" and "default" both
881 // add the necessary bytecode before the reference.
882 if (b)
883 b->AddMarkReference (m);
884 else
885 w->AddReference (m);
886
887 // Init a buffer for the case block and tell the object
888 // writer to record all written data to it.
889 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer;
890 }

mercurial