162 MustNext (";"); |
165 MustNext (";"); |
163 continue; |
166 continue; |
164 } |
167 } |
165 |
168 |
166 if (!token.compare ("}")) { |
169 if (!token.compare ("}")) { |
|
170 printf ("parse closing brace\n"); |
167 // Closing brace |
171 // Closing brace |
168 int dataheader = (g_CurMode == MODE_EVENT) ? DH_ENDEVENT : |
172 int dataheader = (g_CurMode == MODE_EVENT) ? DH_ENDEVENT : |
169 (g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP : |
173 (g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP : |
170 (g_CurMode == MODE_ONENTER) ? DH_ENDONENTER : |
174 (g_CurMode == MODE_ONENTER) ? DH_ENDONENTER : |
171 (g_CurMode == MODE_ONEXIT) ? DH_ENDONEXIT : -1; |
175 (g_CurMode == MODE_ONEXIT) ? DH_ENDONEXIT : -1; |
172 |
176 |
173 if (dataheader == -1) |
177 if (dataheader == -1) |
174 ParserError ("unexpected `}`"); |
178 ParserError ("unexpected `}`"); |
175 |
179 |
176 // Data header must be written before mode is changed because |
180 // Data header must be written before mode is changed because |
177 // onenter and mainloop go into buffers, and we want the closing |
181 // onenter and mainloop go into special buffers, and we want |
178 // data headers into said buffers too. |
182 // the closing data headers into said buffers too. |
179 w->Write (dataheader); |
183 w->Write (dataheader); |
180 g_CurMode = MODE_TOPLEVEL; |
184 g_CurMode = MODE_TOPLEVEL; |
181 |
185 |
182 if (!PeekNext().compare (";")) |
186 if (!PeekNext().compare (";")) |
183 MustNext (";"); |
187 MustNext (";"); |
184 continue; |
188 continue; |
185 } |
189 } |
186 |
190 |
|
191 // If it's a variable, expect assignment. |
|
192 if (ScriptVar* var = FindGlobalVariable (token)) { |
|
193 DataBuffer* b = ParseAssignment (var); |
|
194 printf ("current token after assignment: `%s`\n", token.chars()); |
|
195 MustNext (";"); |
|
196 w->WriteBuffer (b); |
|
197 delete b; |
|
198 continue; |
|
199 } |
|
200 |
187 // If it's not a keyword, parse it as an expression. |
201 // If it's not a keyword, parse it as an expression. |
|
202 printf ("token length: %d, first char: %c [%d]\n", token.len(), token.chars()[0], token.chars()[0]); |
188 DataBuffer* b = ParseExpression (TYPE_VOID); |
203 DataBuffer* b = ParseExpression (TYPE_VOID); |
189 w->WriteBuffer (b); |
204 w->WriteBuffer (b); |
190 delete b; |
205 delete b; |
191 printf ("expression done!\n"); |
206 printf ("expression done! current token is %s\n", token.chars()); |
192 MustThis (";"); |
207 MustNext (";"); |
193 } |
208 } |
194 |
209 |
195 if (g_CurMode != MODE_TOPLEVEL) |
210 if (g_CurMode != MODE_TOPLEVEL) |
196 ParserError ("script did not end at top level; did you forget a `}`?"); |
211 ParserError ("script did not end at top level; did you forget a `}`?"); |
197 |
212 |
205 // String table |
220 // String table |
206 w->WriteStringTable (); |
221 w->WriteStringTable (); |
207 } |
222 } |
208 |
223 |
209 // ============================================================================ |
224 // ============================================================================ |
210 // Parses a given command |
225 // Parses a command call |
211 DataBuffer* ScriptReader::ParseCommand (CommandDef* comm) { |
226 DataBuffer* ScriptReader::ParseCommand (CommandDef* comm) { |
212 DataBuffer* r = new DataBuffer(64); |
227 DataBuffer* r = new DataBuffer(64); |
213 // If this was defined at top-level, we stop right at square one! |
|
214 if (g_CurMode == MODE_TOPLEVEL) |
228 if (g_CurMode == MODE_TOPLEVEL) |
215 ParserError ("no commands allowed at top level!"); |
229 ParserError ("command call at top level"); |
216 |
230 |
|
231 printf ("\n\n\n=====================================\nBEGIN PARSING COMMAND\n"); |
217 printf ("token: %s\n", token.chars()); |
232 printf ("token: %s\n", token.chars()); |
218 MustNext ("("); |
233 MustNext ("("); |
|
234 MustNext (); |
219 |
235 |
220 int curarg = 0; |
236 int curarg = 0; |
221 while (1) { |
237 while (1) { |
|
238 printf ("at argument %d\n", curarg); |
|
239 printf ("next token: %s\n", token.chars()); |
|
240 |
222 if (!token.compare (")")) { |
241 if (!token.compare (")")) { |
223 printf ("closing command with token `%s`\n", token.chars()); |
242 printf ("closing command with token `%s`\n", token.chars()); |
224 if (curarg < comm->numargs - 1) |
243 if (curarg < comm->numargs - 1) |
225 ParserError ("too few arguments passed to %s\n", comm->name.chars()); |
244 ParserError ("too few arguments passed to %s\n", comm->name.chars()); |
226 break; |
245 break; |
227 curarg++; |
246 curarg++; |
228 } |
247 } |
229 printf ("prev token: %s\n", token.chars()); |
|
230 MustNext (); |
|
231 printf ("next token: %s\n", token.chars()); |
|
232 |
|
233 // jump back to start |
|
234 if (!token.compare (")")) |
|
235 continue; |
|
236 |
248 |
237 if (curarg >= comm->maxargs) |
249 if (curarg >= comm->maxargs) |
238 ParserError ("too many arguments passed to %s\n", comm->name.chars()); |
250 ParserError ("too many arguments passed to %s\n", comm->name.chars()); |
239 |
251 |
240 r->Merge (ParseExpression (comm->argtypes[curarg])); |
252 r->Merge (ParseExpression (comm->argtypes[curarg])); |
|
253 MustNext (); |
|
254 printf ("after expression, token is `%s`\n", token.chars()); |
241 |
255 |
242 if (curarg < comm->numargs - 1) { |
256 if (curarg < comm->numargs - 1) { |
243 MustThis (","); |
257 MustThis (","); |
|
258 MustNext (); |
244 } else if (curarg < comm->maxargs - 1) { |
259 } else if (curarg < comm->maxargs - 1) { |
245 // Can continue, but can terminate as well. |
260 // Can continue, but can terminate as well. |
246 if (!token.compare (")")) { |
261 if (!token.compare (")")) { |
247 curarg++; |
262 curarg++; |
248 break; |
263 break; |
249 } else |
264 } else { |
250 MustThis (","); |
265 MustThis (","); |
|
266 MustNext (); |
|
267 } |
251 } |
268 } |
252 |
269 |
253 curarg++; |
270 curarg++; |
254 } |
271 } |
255 |
272 |
256 // If the script skipped any optional arguments, fill in defaults. |
273 // If the script skipped any optional arguments, fill in defaults. |
257 while (curarg < comm->maxargs) { |
274 while (curarg < comm->maxargs) { |
258 r->Write<byte> (DH_PUSHNUMBER); |
275 r->Write<word> (DH_PUSHNUMBER); |
259 r->Write<byte> (comm->defvals[curarg]); |
276 r->Write<word> (comm->defvals[curarg]); |
260 curarg++; |
277 curarg++; |
261 } |
278 } |
262 |
279 |
263 r->Write<byte> (DH_COMMAND); |
280 r->Write<word> (DH_COMMAND); |
264 r->Write<byte> (comm->number); |
281 r->Write<word> (comm->number); |
265 r->Write<byte> (comm->maxargs); |
282 r->Write<word> (comm->maxargs); |
266 |
283 |
267 printf ("command complete\n"); |
284 printf ("command complete\n"); |
268 return r; |
285 return r; |
269 } |
286 } |
270 |
287 |
|
288 // ============================================================================ |
|
289 // Is the given operator an assignment operator? |
271 static bool IsAssignmentOperator (int oper) { |
290 static bool IsAssignmentOperator (int oper) { |
272 switch (oper) { |
291 switch (oper) { |
273 case OPER_ASSIGNADD: |
292 case OPER_ASSIGNADD: |
274 case OPER_ASSIGNSUB: |
293 case OPER_ASSIGNSUB: |
275 case OPER_ASSIGNMUL: |
294 case OPER_ASSIGNMUL: |
310 error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper); |
330 error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper); |
311 return 0; |
331 return 0; |
312 } |
332 } |
313 |
333 |
314 // ============================================================================ |
334 // ============================================================================ |
315 // Parses an expression |
335 // Parses an expression, potentially recursively |
316 DataBuffer* ScriptReader::ParseExpression (int reqtype) { |
336 DataBuffer* ScriptReader::ParseExpression (int reqtype) { |
317 printf ("begin parsing expression. this token is `%s`, next token is `%s`\n", |
337 printf ("begin parsing expression. this token is `%s`, next token is `%s`\n", |
318 token.chars(), PeekNext().chars()); |
338 token.chars(), PeekNext().chars()); |
319 DataBuffer* retbuf = new DataBuffer (64); |
339 DataBuffer* retbuf = new DataBuffer (64); |
320 |
340 |
321 DataBuffer* lb = NULL; |
341 DataBuffer* lb = NULL; |
322 |
342 |
|
343 // If it's a variable, note it down - we need to do special checks with it later. |
323 ScriptVar* var = FindGlobalVariable (token); |
344 ScriptVar* var = FindGlobalVariable (token); |
324 if (var) { |
345 |
325 MustNext (); |
346 lb = ParseExprValue (reqtype); |
326 if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction |
|
327 ParserError ("can't alter variables at top level"); |
|
328 reqtype = TYPE_INT; |
|
329 } else |
|
330 lb = ParseExprValue (reqtype); |
|
331 printf ("done\n"); |
347 printf ("done\n"); |
332 |
348 |
333 // Get an operator |
349 // Get an operator |
334 printf ("parse operator at token %s\n", token.chars()); |
350 printf ("parse operator at token %s\n", token.chars()); |
335 int oper = ParseOperator (); |
351 int oper = ParseOperator (true); |
|
352 printf ("operator parsed: token is now %s\n", token.chars()); |
336 printf ("got %d\n", oper); |
353 printf ("got %d\n", oper); |
|
354 |
337 // No operator found - stop here. |
355 // No operator found - stop here. |
338 if (oper == -1) { |
356 if (oper == -1) { |
339 retbuf->Merge (lb); |
357 retbuf->Merge (lb); |
340 printf ("expression complete without operator, stopping at `%s`\n", token.chars()); |
358 printf ("expression complete without operator, stopping at `%s`\n", token.chars()); |
341 return retbuf; |
359 return retbuf; |
342 } |
360 } |
343 |
361 |
|
362 // We peeked the operator, move forward now |
|
363 MustNext(); |
|
364 |
|
365 // Can't be an assignement operator, those belong in assignments. |
|
366 if (IsAssignmentOperator (oper)) |
|
367 ParserError ("assignment operator inside expressions"); |
|
368 |
344 // Parse the right operand, |
369 // Parse the right operand, |
345 printf ("parse right operand\n"); |
370 printf ("parse right operand\n"); |
346 MustNext (); |
371 MustNext (); |
347 DataBuffer* rb = ParseExprValue (reqtype); |
372 DataBuffer* rb = ParseExprValue (reqtype); |
348 printf ("done\n"); |
373 printf ("done\n"); |
349 |
374 |
|
375 retbuf->Merge (rb); |
350 retbuf->Merge (lb); |
376 retbuf->Merge (lb); |
351 retbuf->Merge (rb); |
|
352 |
377 |
353 long dh = DataHeaderByOperator (var, oper); |
378 long dh = DataHeaderByOperator (var, oper); |
354 retbuf->Write<byte> (dh); |
379 retbuf->Write<word> (dh); |
355 |
|
356 if (IsAssignmentOperator (oper)) |
|
357 retbuf->Write<byte> (var->index); |
|
358 |
380 |
359 printf ("expression complete\n"); |
381 printf ("expression complete\n"); |
360 return retbuf; |
382 return retbuf; |
361 } |
383 } |
362 |
384 |
363 // ============================================================================ |
385 // ============================================================================ |
364 // Parsess an operator from tokens and returns an identifier. |
386 // Parses an operator string. Returns the operator number code. |
365 int ScriptReader::ParseOperator () { |
387 int ScriptReader::ParseOperator (bool peek) { |
366 str oper; |
388 str oper; |
367 oper += PeekNext (); |
389 if (peek) |
|
390 oper += PeekNext (); |
|
391 else |
|
392 oper += token; |
368 |
393 |
369 // Check one-char operators |
394 // Check one-char operators |
370 int o = !oper.compare ("=") ? OPER_ASSIGN : |
395 int o = !oper.compare ("=") ? OPER_ASSIGN : |
371 !oper.compare ("+") ? OPER_ADD : |
396 !oper.compare ("+") ? OPER_ADD : |
372 !oper.compare ("-") ? OPER_SUBTRACT : |
397 !oper.compare ("-") ? OPER_SUBTRACT : |
374 !oper.compare ("/") ? OPER_DIVIDE : |
399 !oper.compare ("/") ? OPER_DIVIDE : |
375 !oper.compare ("%") ? OPER_MODULUS : |
400 !oper.compare ("%") ? OPER_MODULUS : |
376 -1; |
401 -1; |
377 |
402 |
378 if (o != -1) { |
403 if (o != -1) { |
379 MustNext (); |
|
380 return o; |
404 return o; |
381 } |
405 } |
382 |
406 |
383 // Two-char operators |
407 // Two-char operators |
384 MustNext (); |
408 oper += PeekNext (peek ? 1 : 0); |
385 oper += PeekNext (1); |
|
386 |
409 |
387 o = !oper.compare ("+=") ? OPER_ASSIGNADD : |
410 o = !oper.compare ("+=") ? OPER_ASSIGNADD : |
388 !oper.compare ("-=") ? OPER_ASSIGNSUB : |
411 !oper.compare ("-=") ? OPER_ASSIGNSUB : |
389 !oper.compare ("*=") ? OPER_ASSIGNMUL : |
412 !oper.compare ("*=") ? OPER_ASSIGNMUL : |
390 !oper.compare ("/=") ? OPER_ASSIGNDIV : |
413 !oper.compare ("/=") ? OPER_ASSIGNDIV : |
391 !oper.compare ("%=") ? OPER_ASSIGNMOD : |
414 !oper.compare ("%=") ? OPER_ASSIGNMOD : |
392 -1; |
415 -1; |
393 |
416 |
394 if (o != -1) { |
417 if (o != -1) |
395 MustNext (); |
418 MustNext (); |
396 MustNext (); |
|
397 } |
|
398 |
419 |
399 return o; |
420 return o; |
400 } |
421 } |
401 |
422 |
402 // ============================================================================ |
423 // ============================================================================ |
421 delete b; |
442 delete b; |
422 |
443 |
423 // Command |
444 // Command |
424 if (reqtype && comm->returnvalue != reqtype) |
445 if (reqtype && comm->returnvalue != reqtype) |
425 ParserError ("%s returns an incompatible data type", comm->name.chars()); |
446 ParserError ("%s returns an incompatible data type", comm->name.chars()); |
426 return ParseCommand (comm); |
447 b = ParseCommand (comm); |
427 } else if ((g = FindGlobalVariable (token)) && reqtype != TYPE_STRING) { |
448 } else if ((g = FindGlobalVariable (token)) && reqtype != TYPE_STRING) { |
428 printf ("value is a global var\n"); |
449 printf ("value is a global var\n"); |
429 // Global variable |
450 // Global variable |
430 b->Write<byte> (DH_PUSHGLOBALVAR); |
451 b->Write<word> (DH_PUSHGLOBALVAR); |
431 b->Write<byte> (g->index); |
452 b->Write<word> (g->index); |
432 } else { |
453 } else { |
433 printf ("value is a literal\n"); |
454 printf ("value is a literal\n"); |
434 // If nothing else, check for literal |
455 // If nothing else, check for literal |
435 switch (reqtype) { |
456 switch (reqtype) { |
436 case TYPE_VOID: |
457 case TYPE_VOID: |
437 ParserError ("bad syntax"); |
458 ParserError ("bad syntax"); |
438 break; |
459 break; |
439 case TYPE_INT: { |
460 case TYPE_INT: { |
440 printf ("value is an integer literal\n"); |
|
441 /* if (!token.isnumber ()) |
|
442 ParserError ("expected an integer, got `%s`", token.chars()); |
|
443 */ |
|
444 MustNumber (true); |
461 MustNumber (true); |
445 printf ("literal is `%s` = %d\n", token.chars(), atoi (token.chars())); |
|
446 |
462 |
447 // All values are written unsigned - thus we need to write the value's |
463 // All values are written unsigned - thus we need to write the value's |
448 // absolute value, followed by an unary minus if it was negative. |
464 // absolute value, followed by an unary minus if it was negative. |
449 b->Write<byte> (DH_PUSHNUMBER); |
465 b->Write<word> (DH_PUSHNUMBER); |
450 long v = atoi (token.chars ()); |
466 long v = atoi (token.chars ()); |
451 b->Write<byte> (static_cast<byte> (abs (v))); |
467 b->Write<word> (static_cast<word> (abs (v))); |
452 if (v < 0) { |
468 if (v < 0) |
453 printf ("%ld is negative, write abs value %d and unary minus\n", v, abs(v)); |
469 b->Write<word> (DH_UNARYMINUS); |
454 b->Write<byte> (DH_UNARYMINUS); |
|
455 } |
|
456 break; |
470 break; |
457 } |
471 } |
458 case TYPE_STRING: |
472 case TYPE_STRING: |
459 // PushToStringTable either returns the string index of the |
473 // PushToStringTable either returns the string index of the |
460 // string if it finds it in the table, or writes it to the |
474 // string if it finds it in the table, or writes it to the |
461 // table and returns it index if it doesn't find it there. |
475 // table and returns it index if it doesn't find it there. |
462 printf ("value is a string literal\n"); |
476 printf ("value is a string literal\n"); |
463 MustString (true); |
477 MustString (true); |
464 b->Write<byte> (DH_PUSHSTRINGINDEX); |
478 b->Write<word> (DH_PUSHSTRINGINDEX); |
465 b->Write<byte> (PushToStringTable (token.chars())); |
479 b->Write<word> (PushToStringTable (token.chars())); |
466 break; |
480 break; |
467 } |
481 } |
468 } |
482 } |
|
483 printf ("value parsed: current token is `%s`\n", token.chars()); |
469 |
484 |
470 return b; |
485 return b; |
471 } |
486 } |
|
487 |
|
488 // ============================================================================ |
|
489 // Parses an assignment. An assignment starts with a variable name, followed |
|
490 // by an assignment operator, followed by an expression value. Expects current |
|
491 // token to be the name of the variable, and expects the variable to be given. |
|
492 DataBuffer* ScriptReader::ParseAssignment (ScriptVar* var) { |
|
493 printf ("ASSIGNMENT: this token is `%s`, next token is `%s`\n", |
|
494 token.chars(), PeekNext().chars()); |
|
495 |
|
496 // Get an operator |
|
497 printf ("parse assignment operator at token %s\n", token.chars()); |
|
498 |
|
499 MustNext (); |
|
500 int oper = ParseOperator (); |
|
501 if (!IsAssignmentOperator (oper)) |
|
502 ParserError ("expected assignment operator"); |
|
503 printf ("got %d\n", oper); |
|
504 |
|
505 if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction |
|
506 ParserError ("can't alter variables at top level"); |
|
507 |
|
508 // Parse the right operand, |
|
509 printf ("parse right operand\n"); |
|
510 MustNext (); |
|
511 DataBuffer* retbuf = ParseExprValue (TYPE_INT); |
|
512 |
|
513 long dh = DataHeaderByOperator (var, oper); |
|
514 retbuf->Write<word> (dh); |
|
515 retbuf->Write<word> (var->index); |
|
516 |
|
517 printf ("assignment complete\n"); |
|
518 return retbuf; |
|
519 } |