| 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::BeginParse (ObjWriter* w) { |
| 74 while (Next()) { |
74 while (Next()) { |
| |
75 // ============================================================ |
| 75 if (!token.icompare ("state")) { |
76 if (!token.icompare ("state")) { |
| 76 MUST_TOPLEVEL |
77 MUST_TOPLEVEL |
| 77 |
78 |
| 78 MustString (); |
79 MustString (); |
| 79 |
80 |
| 124 w->Write<word> (e->number); |
126 w->Write<word> (e->number); |
| 125 g_NumEvents++; |
127 g_NumEvents++; |
| 126 continue; |
128 continue; |
| 127 } |
129 } |
| 128 |
130 |
| |
131 // ============================================================ |
| 129 if (!token.icompare ("mainloop")) { |
132 if (!token.icompare ("mainloop")) { |
| 130 MUST_TOPLEVEL |
133 MUST_TOPLEVEL |
| 131 MustNext ("{"); |
134 MustNext ("{"); |
| 132 |
135 |
| 133 // Mode must be set before dataheader is written here! |
136 // Mode must be set before dataheader is written here! |
| 134 g_CurMode = MODE_MAINLOOP; |
137 g_CurMode = MODE_MAINLOOP; |
| 135 w->Write (DH_MAINLOOP); |
138 w->Write (DH_MAINLOOP); |
| 136 continue; |
139 continue; |
| 137 } |
140 } |
| 138 |
141 |
| |
142 // ============================================================ |
| 139 if (!token.icompare ("onenter") || !token.icompare ("onexit")) { |
143 if (!token.icompare ("onenter") || !token.icompare ("onexit")) { |
| 140 MUST_TOPLEVEL |
144 MUST_TOPLEVEL |
| 141 bool onenter = !token.compare ("onenter"); |
145 bool onenter = !token.compare ("onenter"); |
| 142 MustNext ("{"); |
146 MustNext ("{"); |
| 143 |
147 |
| 146 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
150 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
| 147 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
151 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
| 148 continue; |
152 continue; |
| 149 } |
153 } |
| 150 |
154 |
| |
155 // ============================================================ |
| 151 if (!token.compare ("var")) { |
156 if (!token.compare ("var")) { |
| 152 // For now, only globals are supported |
157 // For now, only globals are supported |
| 153 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
158 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
| 154 ParserError ("variables must only be global for now"); |
159 ParserError ("variables must only be global for now"); |
| 155 |
160 |
| 268 blockstack[g_BlockStackCursor].mark2 = mark2; |
277 blockstack[g_BlockStackCursor].mark2 = mark2; |
| 269 blockstack[g_BlockStackCursor].type = BLOCKTYPE_WHILE; |
278 blockstack[g_BlockStackCursor].type = BLOCKTYPE_WHILE; |
| 270 continue; |
279 continue; |
| 271 } |
280 } |
| 272 |
281 |
| |
282 // ============================================================ |
| |
283 // For loop |
| |
284 if (!token.icompare ("for")) { |
| |
285 MUST_NOT_TOPLEVEL |
| |
286 PushBlockStack (); |
| |
287 |
| |
288 // Initializer |
| |
289 MustNext ("("); |
| |
290 MustNext (); |
| |
291 DataBuffer* init = ParseStatement (w); |
| |
292 MustNext (";"); |
| |
293 |
| |
294 // Condition |
| |
295 MustNext (); |
| |
296 DataBuffer* cond = ParseExpression (TYPE_INT); |
| |
297 MustNext (";"); |
| |
298 |
| |
299 // Incrementor |
| |
300 MustNext (); |
| |
301 DataBuffer* incr = ParseStatement (w); |
| |
302 MustNext (")"); |
| |
303 MustNext ("{"); |
| |
304 |
| |
305 // First, write out the initializer |
| |
306 w->WriteBuffer (init); |
| |
307 |
| |
308 // Init two marks |
| |
309 int mark1 = w->AddMark (MARKTYPE_INTERNAL, ""); |
| |
310 int mark2 = w->AddMark (MARKTYPE_INTERNAL, ""); |
| |
311 |
| |
312 // Add the condition |
| |
313 w->WriteBuffer (cond); |
| |
314 w->Write<long> (DH_IFNOTGOTO); |
| |
315 w->AddReference (mark2); |
| |
316 |
| |
317 // Store the marks and incrementor |
| |
318 blockstack[g_BlockStackCursor].mark1 = mark1; |
| |
319 blockstack[g_BlockStackCursor].mark2 = mark2; |
| |
320 blockstack[g_BlockStackCursor].buffer1 = incr; |
| |
321 blockstack[g_BlockStackCursor].type = BLOCKTYPE_FOR; |
| |
322 continue; |
| |
323 } |
| |
324 |
| |
325 // ============================================================ |
| 273 if (!token.compare ("}")) { |
326 if (!token.compare ("}")) { |
| 274 // Closing brace |
327 // Closing brace |
| 275 |
328 |
| 276 // If we're in the block stack, we're descending down from it now |
329 // If we're in the block stack, we're descending down from it now |
| 277 if (g_BlockStackCursor > 0) { |
330 if (g_BlockStackCursor > 0) { |
| 279 switch (info->type) { |
332 switch (info->type) { |
| 280 case BLOCKTYPE_IF: |
333 case BLOCKTYPE_IF: |
| 281 // Adjust the closing mark. |
334 // Adjust the closing mark. |
| 282 w->MoveMark (info->mark1); |
335 w->MoveMark (info->mark1); |
| 283 break; |
336 break; |
| |
337 case BLOCKTYPE_FOR: |
| |
338 // Write the incrementor at the end of the loop block |
| |
339 w->WriteBuffer (info->buffer1); |
| |
340 // fall-thru |
| 284 case BLOCKTYPE_WHILE: |
341 case BLOCKTYPE_WHILE: |
| 285 // Write down the instruction to go back to the start of the loop |
342 // Write down the instruction to go back to the start of the loop |
| 286 w->Write (DH_GOTO); |
343 w->Write (DH_GOTO); |
| 287 w->AddReference (info->mark1); |
344 w->AddReference (info->mark1); |
| 288 |
345 |
| 312 if (!PeekNext().compare (";")) |
369 if (!PeekNext().compare (";")) |
| 313 MustNext (";"); |
370 MustNext (";"); |
| 314 continue; |
371 continue; |
| 315 } |
372 } |
| 316 |
373 |
| 317 // If it's a variable, expect assignment. |
374 // ============================================================ |
| 318 if (ScriptVar* var = FindGlobalVariable (token)) { |
375 // If nothing else, parse it as a statement (which is either |
| 319 DataBuffer* b = ParseAssignment (var); |
376 // assignment or expression) |
| 320 MustNext (";"); |
377 DataBuffer* b = ParseStatement (w); |
| 321 w->WriteBuffer (b); |
|
| 322 continue; |
|
| 323 } |
|
| 324 |
|
| 325 // If it's not a keyword, parse it as an expression. |
|
| 326 DataBuffer* b = ParseExpression (TYPE_VOID); |
|
| 327 w->WriteBuffer (b); |
378 w->WriteBuffer (b); |
| 328 MustNext (";"); |
379 MustNext (";"); |
| 329 } |
380 } |
| 330 |
381 |
| 331 if (g_CurMode != MODE_TOPLEVEL) |
382 if (g_CurMode != MODE_TOPLEVEL) |
| 620 g_BlockStackCursor++; |
671 g_BlockStackCursor++; |
| 621 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
672 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
| 622 info->type = 0; |
673 info->type = 0; |
| 623 info->mark1 = 0; |
674 info->mark1 = 0; |
| 624 info->mark2 = 0; |
675 info->mark2 = 0; |
| 625 } |
676 info->buffer1 = NULL; |
| |
677 } |
| |
678 |
| |
679 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) { |
| |
680 // If it's a variable, expect assignment. |
| |
681 if (ScriptVar* var = FindGlobalVariable (token)) { |
| |
682 DataBuffer* b = ParseAssignment (var); |
| |
683 return b; |
| |
684 } |
| |
685 |
| |
686 // If it's not a keyword, parse it as an expression. |
| |
687 DataBuffer* b = ParseExpression (TYPE_VOID); |
| |
688 return b; |
| |
689 } |