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 |