| 103 ParserError ("state name must be a single word, got `%s`", token.chars()); |
103 ParserError ("state name must be a single word, got `%s`", token.chars()); |
| 104 str statename = token; |
104 str statename = token; |
| 105 |
105 |
| 106 // stateSpawn is special - it *must* be defined. If we |
106 // stateSpawn is special - it *must* be defined. If we |
| 107 // encountered it, then mark down that we have it. |
107 // encountered it, then mark down that we have it. |
| 108 if (!token.icompare ("statespawn")) |
108 if (-token == "statespawn") |
| 109 g_stateSpawnDefined = true; |
109 g_stateSpawnDefined = true; |
| 110 |
110 |
| 111 // Must end in a colon |
111 // Must end in a colon |
| 112 MustNext (":"); |
112 MustNext (":"); |
| 113 |
113 |
| 171 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
171 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
| 172 continue; |
172 continue; |
| 173 } |
173 } |
| 174 |
174 |
| 175 // ============================================================ |
175 // ============================================================ |
| 176 if (token == "int" || token == "str" || token == "float" || token == "bool") { |
176 if (token == "int" || token == "str" || token == "bool") { |
| 177 // For now, only globals are supported |
177 // For now, only globals are supported |
| 178 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
178 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
| 179 ParserError ("variables must only be global for now"); |
179 ParserError ("variables must only be global for now"); |
| 180 |
180 |
| 181 type_e type = (token == "int") ? TYPE_INT : |
181 type_e type = (token == "int") ? TYPE_INT : |
| 182 (token == "str") ? TYPE_STRING : |
182 (token == "str") ? TYPE_STRING : |
| 183 (token == "float") ? TYPE_FLOAT : |
|
| 184 TYPE_BOOL; |
183 TYPE_BOOL; |
| 185 |
184 |
| 186 MustNext (); |
185 MustNext (); |
| 187 |
186 |
| 188 // Var name must not be a number |
187 // Var name must not be a number |
| 245 // Upon a closing brace, the mark will be adjusted. |
244 // Upon a closing brace, the mark will be adjusted. |
| 246 unsigned int marknum = w->AddMark (""); |
245 unsigned int marknum = w->AddMark (""); |
| 247 |
246 |
| 248 // Use DH_IFNOTGOTO - if the expression is not true, we goto the mark |
247 // Use DH_IFNOTGOTO - if the expression is not true, we goto the mark |
| 249 // we just defined - and this mark will be at the end of the scope block. |
248 // we just defined - and this mark will be at the end of the scope block. |
| 250 w->Write<word> (DH_IFNOTGOTO); |
249 w->Write (DH_IFNOTGOTO); |
| 251 w->AddReference (marknum); |
250 w->AddReference (marknum); |
| 252 |
251 |
| 253 // Store it |
252 // Store it |
| 254 SCOPE(0).mark1 = marknum; |
253 SCOPE(0).mark1 = marknum; |
| 255 SCOPE(0).type = SCOPETYPE_IF; |
254 SCOPE(0).type = SCOPETYPE_IF; |
| 304 |
303 |
| 305 // Write condition |
304 // Write condition |
| 306 w->WriteBuffer (expr); |
305 w->WriteBuffer (expr); |
| 307 |
306 |
| 308 // Instruction to go to the end if it fails |
307 // Instruction to go to the end if it fails |
| 309 w->Write<word> (DH_IFNOTGOTO); |
308 w->Write (DH_IFNOTGOTO); |
| 310 w->AddReference (mark2); |
309 w->AddReference (mark2); |
| 311 |
310 |
| 312 // Store the needed stuff |
311 // Store the needed stuff |
| 313 SCOPE(0).mark1 = mark1; |
312 SCOPE(0).mark1 = mark1; |
| 314 SCOPE(0).mark2 = mark2; |
313 SCOPE(0).mark2 = mark2; |
| 355 int mark1 = w->AddMark (""); |
354 int mark1 = w->AddMark (""); |
| 356 int mark2 = w->AddMark (""); |
355 int mark2 = w->AddMark (""); |
| 357 |
356 |
| 358 // Add the condition |
357 // Add the condition |
| 359 w->WriteBuffer (cond); |
358 w->WriteBuffer (cond); |
| 360 w->Write<word> (DH_IFNOTGOTO); |
359 w->Write (DH_IFNOTGOTO); |
| 361 w->AddReference (mark2); |
360 w->AddReference (mark2); |
| 362 |
361 |
| 363 // Store the marks and incrementor |
362 // Store the marks and incrementor |
| 364 SCOPE(0).mark1 = mark1; |
363 SCOPE(0).mark1 = mark1; |
| 365 SCOPE(0).mark2 = mark2; |
364 SCOPE(0).mark2 = mark2; |
| 430 // for the case block that this heralds, and takes care |
429 // for the case block that this heralds, and takes care |
| 431 // of buffering setup and stuff like that. |
430 // of buffering setup and stuff like that. |
| 432 // NULL the switch buffer for the case-go-to statement, |
431 // NULL the switch buffer for the case-go-to statement, |
| 433 // we want it all under the switch, not into the case-buffers. |
432 // we want it all under the switch, not into the case-buffers. |
| 434 w->SwitchBuffer = NULL; |
433 w->SwitchBuffer = NULL; |
| 435 w->Write<word> (DH_CASEGOTO); |
434 w->Write (DH_CASEGOTO); |
| 436 w->Write<word> (num); |
435 w->Write (num); |
| 437 AddSwitchCase (w, NULL); |
436 AddSwitchCase (w, NULL); |
| 438 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num; |
437 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num; |
| 439 continue; |
438 continue; |
| 440 } |
439 } |
| 441 |
440 |
| 455 // and is only popped when case succeeds, we have |
454 // and is only popped when case succeeds, we have |
| 456 // to pop it with DH_DROP manually if we end up in |
455 // to pop it with DH_DROP manually if we end up in |
| 457 // a default. |
456 // a default. |
| 458 DataBuffer* b = new DataBuffer; |
457 DataBuffer* b = new DataBuffer; |
| 459 SCOPE(0).buffer1 = b; |
458 SCOPE(0).buffer1 = b; |
| 460 b->Write<word> (DH_DROP); |
459 b->Write (DH_DROP); |
| 461 b->Write<word> (DH_GOTO); |
460 b->Write (DH_GOTO); |
| 462 AddSwitchCase (w, b); |
461 AddSwitchCase (w, b); |
| 463 continue; |
462 continue; |
| 464 } |
463 } |
| 465 |
464 |
| 466 // ============================================================ |
465 // ============================================================ |
| 467 // Break statement. |
466 // Break statement. |
| 468 if (token == "break") { |
467 if (token == "break") { |
| 469 if (!g_ScopeCursor) |
468 if (!g_ScopeCursor) |
| 470 ParserError ("unexpected `break`"); |
469 ParserError ("unexpected `break`"); |
| 471 |
470 |
| 472 w->Write<word> (DH_GOTO); |
471 w->Write (DH_GOTO); |
| 473 |
472 |
| 474 // switch and if use mark1 for the closing point, |
473 // switch and if use mark1 for the closing point, |
| 475 // for and while use mark2. |
474 // for and while use mark2. |
| 476 switch (SCOPE(0).type) { |
475 switch (SCOPE(0).type) { |
| 477 case SCOPETYPE_IF: |
476 case SCOPETYPE_IF: |
| 635 MustNext (")"); |
630 MustNext (")"); |
| 636 MustNext (";"); |
631 MustNext (";"); |
| 637 |
632 |
| 638 // If the condition runs true, go back to the start. |
633 // If the condition runs true, go back to the start. |
| 639 w->WriteBuffer (expr); |
634 w->WriteBuffer (expr); |
| 640 w->Write<long> (DH_IFGOTO); |
635 w->Write (DH_IFGOTO); |
| 641 w->AddReference (SCOPE(0).mark1); |
636 w->AddReference (SCOPE(0).mark1); |
| 642 break; |
637 break; |
| 643 } |
638 } |
| 644 case SCOPETYPE_SWITCH: { |
639 case SCOPETYPE_SWITCH: { |
| 645 // Switch closes. Move down to the record buffer of |
640 // Switch closes. Move down to the record buffer of |
| 653 // If not, write instruction to jump to the end of switch after |
648 // If not, write instruction to jump to the end of switch after |
| 654 // the headers (thus won't fall-through if no case matched) |
649 // the headers (thus won't fall-through if no case matched) |
| 655 if (SCOPE(0).buffer1) |
650 if (SCOPE(0).buffer1) |
| 656 w->WriteBuffer (SCOPE(0).buffer1); |
651 w->WriteBuffer (SCOPE(0).buffer1); |
| 657 else { |
652 else { |
| 658 w->Write<word> (DH_DROP); |
653 w->Write (DH_DROP); |
| 659 w->Write<word> (DH_GOTO); |
654 w->Write (DH_GOTO); |
| 660 w->AddReference (SCOPE(0).mark1); |
655 w->AddReference (SCOPE(0).mark1); |
| 661 } |
656 } |
| 662 |
657 |
| 663 // Go through all of the buffers we |
658 // Go through all of the buffers we |
| 664 // recorded down and write them. |
659 // recorded down and write them. |
| 784 curarg++; |
779 curarg++; |
| 785 } |
780 } |
| 786 |
781 |
| 787 // If the script skipped any optional arguments, fill in defaults. |
782 // If the script skipped any optional arguments, fill in defaults. |
| 788 while (curarg < comm->maxargs) { |
783 while (curarg < comm->maxargs) { |
| 789 r->Write<word> (DH_PUSHNUMBER); |
784 r->Write (DH_PUSHNUMBER); |
| 790 r->Write<word> (comm->defvals[curarg]); |
785 r->Write (comm->defvals[curarg]); |
| 791 curarg++; |
786 curarg++; |
| 792 } |
787 } |
| 793 |
788 |
| 794 r->Write<word> (DH_COMMAND); |
789 r->Write (DH_COMMAND); |
| 795 r->Write<word> (comm->number); |
790 r->Write (comm->number); |
| 796 r->Write<word> (comm->maxargs); |
791 r->Write (comm->maxargs); |
| 797 |
792 |
| 798 return r; |
793 return r; |
| 799 } |
794 } |
| 800 |
795 |
| 801 // ============================================================================ |
796 // ============================================================================ |
| 893 // It also is handled differently: there isn't a dataheader for ternary |
888 // It also is handled differently: there isn't a dataheader for ternary |
| 894 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this. |
889 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this. |
| 895 // Behold, big block of writing madness! :P |
890 // Behold, big block of writing madness! :P |
| 896 int mark1 = retbuf->AddMark (""); // start of "else" case |
891 int mark1 = retbuf->AddMark (""); // start of "else" case |
| 897 int mark2 = retbuf->AddMark (""); // end of expression |
892 int mark2 = retbuf->AddMark (""); // end of expression |
| 898 retbuf->Write<word> (DH_IFNOTGOTO); // if the first operand (condition) |
893 retbuf->Write (DH_IFNOTGOTO); // if the first operand (condition) |
| 899 retbuf->AddMarkReference (mark1); // didn't eval true, jump into mark1 |
894 retbuf->AddMarkReference (mark1); // didn't eval true, jump into mark1 |
| 900 retbuf->Merge (rb); // otherwise, perform second operand (true case) |
895 retbuf->Merge (rb); // otherwise, perform second operand (true case) |
| 901 retbuf->Write<word> (DH_GOTO); // afterwards, jump to the end, which is |
896 retbuf->Write (DH_GOTO); // afterwards, jump to the end, which is |
| 902 retbuf->AddMarkReference (mark2); // marked by mark2. |
897 retbuf->AddMarkReference (mark2); // marked by mark2. |
| 903 retbuf->MoveMark (mark1); // move mark1 at the end of the true case |
898 retbuf->MoveMark (mark1); // move mark1 at the end of the true case |
| 904 retbuf->Merge (tb); // perform third operand (false case) |
899 retbuf->Merge (tb); // perform third operand (false case) |
| 905 retbuf->MoveMark (mark2); // move the ending mark2 here |
900 retbuf->MoveMark (mark2); // move the ending mark2 here |
| 906 } else { |
901 } else { |
| 907 // Write to buffer |
902 // Write to buffer |
| 908 retbuf->Merge (rb); |
903 retbuf->Merge (rb); |
| 909 retbuf->Write<word> (DataHeaderByOperator (NULL, oper)); |
904 retbuf->Write (DataHeaderByOperator (NULL, oper)); |
| 910 } |
905 } |
| 911 } |
906 } |
| 912 |
907 |
| 913 return retbuf; |
908 return retbuf; |
| 914 } |
909 } |
| 1026 ParserError ("strlen only works with const str"); |
1021 ParserError ("strlen only works with const str"); |
| 1027 |
1022 |
| 1028 if (reqtype != TYPE_INT) |
1023 if (reqtype != TYPE_INT) |
| 1029 ParserError ("strlen returns int but %s is expected\n", (char*)GetTypeName (reqtype)); |
1024 ParserError ("strlen returns int but %s is expected\n", (char*)GetTypeName (reqtype)); |
| 1030 |
1025 |
| 1031 b->Write<word> (DH_PUSHNUMBER); |
1026 b->Write (DH_PUSHNUMBER); |
| 1032 b->Write<word> (constant->val.len ()); |
1027 b->Write (constant->val.len ()); |
| 1033 |
1028 |
| 1034 MustNext (")"); |
1029 MustNext (")"); |
| 1035 } else if (token == "(") { |
1030 } else if (token == "(") { |
| 1036 // Expression |
1031 // Expression |
| 1037 MustNext (); |
1032 MustNext (); |
| 1053 (char*)GetTypeName (reqtype)); |
1048 (char*)GetTypeName (reqtype)); |
| 1054 |
1049 |
| 1055 switch (constant->type) { |
1050 switch (constant->type) { |
| 1056 case TYPE_BOOL: |
1051 case TYPE_BOOL: |
| 1057 case TYPE_INT: |
1052 case TYPE_INT: |
| 1058 b->Write<word> (DH_PUSHNUMBER); |
1053 b->Write (DH_PUSHNUMBER); |
| 1059 b->Write<word> (atoi (constant->val)); |
1054 b->Write (atoi (constant->val)); |
| 1060 break; |
|
| 1061 case TYPE_FLOAT: |
|
| 1062 b->WriteFloat (constant->val); |
|
| 1063 break; |
1055 break; |
| 1064 case TYPE_STRING: |
1056 case TYPE_STRING: |
| 1065 b->WriteString (constant->val); |
1057 b->WriteString (constant->val); |
| 1066 break; |
1058 break; |
| 1067 case TYPE_VOID: |
1059 case TYPE_VOID: |
| 1068 case TYPE_UNKNOWN: |
1060 case TYPE_UNKNOWN: |
| 1069 break; |
1061 break; |
| 1070 } |
1062 } |
| 1071 } else if ((g = FindGlobalVariable (token))) { |
1063 } else if ((g = FindGlobalVariable (token))) { |
| 1072 // Global variable |
1064 // Global variable |
| 1073 b->Write<word> (DH_PUSHGLOBALVAR); |
1065 b->Write (DH_PUSHGLOBALVAR); |
| 1074 b->Write<word> (g->index); |
1066 b->Write (g->index); |
| 1075 } else { |
1067 } else { |
| 1076 // If nothing else, check for literal |
1068 // If nothing else, check for literal |
| 1077 switch (reqtype) { |
1069 switch (reqtype) { |
| 1078 case TYPE_VOID: |
1070 case TYPE_VOID: |
| 1079 case TYPE_UNKNOWN: |
1071 case TYPE_UNKNOWN: |
| 1083 case TYPE_INT: { |
1075 case TYPE_INT: { |
| 1084 MustNumber (true); |
1076 MustNumber (true); |
| 1085 |
1077 |
| 1086 // All values are written unsigned - thus we need to write the value's |
1078 // All values are written unsigned - thus we need to write the value's |
| 1087 // absolute value, followed by an unary minus for negatives. |
1079 // absolute value, followed by an unary minus for negatives. |
| 1088 b->Write<word> (DH_PUSHNUMBER); |
1080 b->Write (DH_PUSHNUMBER); |
| 1089 |
1081 |
| 1090 long v = atol (token); |
1082 long v = atol (token); |
| 1091 b->Write<word> (static_cast<word> (abs (v))); |
1083 b->Write (static_cast<word> (abs (v))); |
| 1092 if (v < 0) |
1084 if (v < 0) |
| 1093 b->Write<word> (DH_UNARYMINUS); |
1085 b->Write (DH_UNARYMINUS); |
| 1094 break; |
1086 break; |
| 1095 } |
1087 } |
| 1096 case TYPE_STRING: |
1088 case TYPE_STRING: |
| 1097 // PushToStringTable either returns the string index of the |
1089 // PushToStringTable either returns the string index of the |
| 1098 // string if it finds it in the table, or writes it to the |
1090 // string if it finds it in the table, or writes it to the |
| 1099 // table and returns it index if it doesn't find it there. |
1091 // table and returns it index if it doesn't find it there. |
| 1100 MustString (true); |
1092 MustString (true); |
| 1101 b->WriteString (token); |
1093 b->WriteString (token); |
| 1102 break; |
1094 break; |
| 1103 case TYPE_FLOAT: { |
|
| 1104 str floatstring = ParseFloat (); |
|
| 1105 |
|
| 1106 // TODO: Keep this check after decimal loss is fixed, but make |
|
| 1107 // it a real precision loss check. 55.5123 -> 55.512299, this |
|
| 1108 // should probably be warned of. |
|
| 1109 float check = static_cast<float> (static_cast<word> (atof (floatstring))); |
|
| 1110 if (atof (floatstring) != check) |
|
| 1111 ParserWarning ("floating point number %f loses precision (-> %f)", |
|
| 1112 atof (floatstring), check); |
|
| 1113 |
|
| 1114 b->WriteFloat (floatstring); |
|
| 1115 break; |
|
| 1116 } |
|
| 1117 } |
1095 } |
| 1118 } |
1096 } |
| 1119 |
1097 |
| 1120 // Negate it now if desired |
1098 // Negate it now if desired |
| 1121 if (negate) |
1099 if (negate) |
| 1122 b->Write<word> (DH_NEGATELOGICAL); |
1100 b->Write (DH_NEGATELOGICAL); |
| 1123 |
1101 |
| 1124 return b; |
1102 return b; |
| 1125 } |
1103 } |
| 1126 |
1104 |
| 1127 // ============================================================================ |
1105 // ============================================================================ |
| 1147 |
1125 |
| 1148 // <<= and >>= do not have data headers. Solution: expand them. |
1126 // <<= and >>= do not have data headers. Solution: expand them. |
| 1149 // a <<= b -> a = a << b |
1127 // a <<= b -> a = a << b |
| 1150 // a >>= b -> a = a >> b |
1128 // a >>= b -> a = a >> b |
| 1151 if (oper == OPER_ASSIGNLEFTSHIFT || oper == OPER_ASSIGNRIGHTSHIFT) { |
1129 if (oper == OPER_ASSIGNLEFTSHIFT || oper == OPER_ASSIGNRIGHTSHIFT) { |
| 1152 retbuf->Write<word> (global ? DH_PUSHGLOBALVAR : DH_PUSHLOCALVAR); |
1130 retbuf->Write (global ? DH_PUSHGLOBALVAR : DH_PUSHLOCALVAR); |
| 1153 retbuf->Write<word> (var->index); |
1131 retbuf->Write (var->index); |
| 1154 retbuf->Merge (expr); |
1132 retbuf->Merge (expr); |
| 1155 retbuf->Write<word> ((oper == OPER_ASSIGNLEFTSHIFT) ? DH_LSHIFT : DH_RSHIFT); |
1133 retbuf->Write ((oper == OPER_ASSIGNLEFTSHIFT) ? DH_LSHIFT : DH_RSHIFT); |
| 1156 retbuf->Write<word> (global ? DH_ASSIGNGLOBALVAR : DH_ASSIGNLOCALVAR); |
1134 retbuf->Write (global ? DH_ASSIGNGLOBALVAR : DH_ASSIGNLOCALVAR); |
| 1157 retbuf->Write<word> (var->index); |
1135 retbuf->Write (var->index); |
| 1158 } else { |
1136 } else { |
| 1159 retbuf->Merge (expr); |
1137 retbuf->Merge (expr); |
| 1160 long dh = DataHeaderByOperator (var, oper); |
1138 long dh = DataHeaderByOperator (var, oper); |
| 1161 retbuf->Write<word> (dh); |
1139 retbuf->Write (dh); |
| 1162 retbuf->Write<word> (var->index); |
1140 retbuf->Write (var->index); |
| 1163 } |
1141 } |
| 1164 |
1142 |
| 1165 return retbuf; |
1143 return retbuf; |
| 1166 } |
1144 } |
| 1167 |
1145 |