@@ -609,7 +609,7 @@ struct VirtualMachine {
609609 // Create local variables and commands.
610610 for (int32_t c = 0 ; c < unresolvedMethod.commands .length (); c++) {
611611 const UnresolvedCommand &unresolvedCommand = unresolvedMethod.commands [c];
612- this ->generateLabelsAndStatements (methodIndex, initMethodIndex, unresolvedProgram, unresolvedMethod, unresolvedCommand.command , unresolvedCommand.arguments , global);
612+ this ->generateMachineCode (methodIndex, initMethodIndex, unresolvedProgram, unresolvedMethod, unresolvedCommand.command , unresolvedCommand.arguments , global);
613613 }
614614 this ->addReturnInstruction (methodIndex);
615615 #ifdef VIRTUAL_MACHINE_DEBUG_PRINT
@@ -898,81 +898,89 @@ struct VirtualMachine {
898898 throwError (message);
899899 }
900900
901- // TODO: Inline into declareVariable
902- Variable<TYPE_COUNT>* declareVariable_aux (const VMTypeDef<TYPE_COUNT>& typeDef, int32_t methodIndex, AccessType access, const ReadableString& name, bool initialize, const ReadableString& defaultValueText, bool global) {
903- // Make commonly used data more readable
904- Method<TYPE_COUNT>* currentMethod = &this ->methods [methodIndex];
905-
906- // Assert correctness
907- if (global && (access == AccessType::Input || access == AccessType::Output)) {
908- throwError (U" Cannot declare inputs or outputs globally!\n " );
909- }
910-
911- // Count how many variables the method has of each type
912- currentMethod->count [typeDef.dataType ]++;
913- this ->methods [methodIndex].unifiedLocalIndices [typeDef.dataType ].push (this ->methods [methodIndex].locals .length ());
914- // Count inputs for calling the method
915- if (access == AccessType::Input) {
916- if (this ->methods [methodIndex].declaredNonInput ) {
917- throwError (U" Cannot declare input \" " , name, U" \" after a non-input has been declared. Declare inputs, outputs and locals in order.\n " );
918- }
919- this ->methods [methodIndex].inputCount ++;
920- } else if (access == AccessType::Output) {
921- if (this ->methods [methodIndex].declaredLocals ) {
922- throwError (U" Cannot declare output \" " , name, U" \" after a local has been declared. Declare inputs, outputs and locals in order.\n " );
923- }
924- this ->methods [methodIndex].outputCount ++;
925- this ->methods [methodIndex].declaredNonInput = true ;
926- } else if (access == AccessType::Hidden) {
927- this ->methods [methodIndex].declaredLocals = true ;
928- this ->methods [methodIndex].declaredNonInput = true ;
929- }
930- // Declare the variable so that code may find the type and index by name
931- int32_t typeLocalIndex = currentMethod->count [typeDef.dataType ] - 1 ;
932- int32_t globalIndex = typeLocalToGlobalIndex (global, typeLocalIndex);
933- this ->methods [methodIndex].locals .pushConstruct (name, access, &typeDef, typeLocalIndex, global);
934- // If the variable is supposed to be initialized automatically and no value will be given from an input, then we have to initialize it using hidden machine instructions.
935- if (initialize && access != AccessType::Input) {
936- // TODO: Give custom error messages when load or reset was not implemented.
937- // If reset is missing, then the type does not have a default constructor and must have one specified.
938- // If move is missing, then the type does not have a constructor accepting immediate constants.
939- if (string_length (defaultValueText) > 0 ) {
940- // An initial value was provided explicitly.
941- // Look for a load instruction.
942- this ->interpretCommand (methodIndex, U" Move" , List<VMA>(
943- VMA (ArgumentType::Reference, typeDef.dataType , globalIndex),
944- this ->interpretImmediateArgument (this ->memory .getReference (), defaultValueText)
945- ));
946- } else {
947- // No initial value was provided.
948- // Look for a reset instruction.
949- this ->interpretCommand (methodIndex, U" Reset" , List<VMA>(
950- VMA (ArgumentType::Reference, typeDef.dataType , globalIndex)
951- ));
952- }
953- }
954- return &this ->methods [methodIndex].locals .last ();
955- }
956-
957901 Variable<TYPE_COUNT>* declareVariable (int32_t methodIndex, int32_t initMethodIndex, AccessType access, const ReadableString& typeName, const ReadableString& name, bool initialize, const ReadableString& defaultValueText, bool global) {
958902 if (this ->getResource (name, methodIndex, initMethodIndex)) {
959903 throwError (U" A resource named \" " , name, U" \" already exists! Be aware that resource names are case insensitive.\n " );
960904 return nullptr ;
961905 } else {
962906 // Loop over type definitions to find a match
963907 const VMTypeDef<TYPE_COUNT>* typeDef = getMachineType (typeName);
964- if (typeDef) {
908+ if (typeDef != nullptr ) {
965909 if (string_length (defaultValueText) > 0 && !typeDef->allowDefaultValue ) {
966910 throwError (U" The variable \" " , name, U" \" doesn't have an immediate constructor for \" " , typeName, U" \" .\n " );
967911 }
968- return this ->declareVariable_aux (*typeDef, methodIndex, access, name, initialize, defaultValueText, global);
912+ // Declare the variable
913+ Method<TYPE_COUNT>* currentMethod = &this ->methods [methodIndex];
914+ // Assert correctness
915+ if (global && (access == AccessType::Input || access == AccessType::Output)) {
916+ throwError (U" Cannot declare inputs or outputs globally!\n " );
917+ }
918+ // Count how many variables the method has of each type
919+ currentMethod->count [typeDef->dataType ]++;
920+ this ->methods [methodIndex].unifiedLocalIndices [typeDef->dataType ].push (this ->methods [methodIndex].locals .length ());
921+ // Count inputs for calling the method
922+ if (access == AccessType::Input) {
923+ if (this ->methods [methodIndex].declaredNonInput ) {
924+ throwError (U" Cannot declare input \" " , name, U" \" after a non-input has been declared. Declare inputs, outputs and locals in order.\n " );
925+ }
926+ this ->methods [methodIndex].inputCount ++;
927+ } else if (access == AccessType::Output) {
928+ if (this ->methods [methodIndex].declaredLocals ) {
929+ throwError (U" Cannot declare output \" " , name, U" \" after a local has been declared. Declare inputs, outputs and locals in order.\n " );
930+ }
931+ this ->methods [methodIndex].outputCount ++;
932+ this ->methods [methodIndex].declaredNonInput = true ;
933+ } else if (access == AccessType::Hidden) {
934+ this ->methods [methodIndex].declaredLocals = true ;
935+ this ->methods [methodIndex].declaredNonInput = true ;
936+ }
937+ // Declare the variable so that code may find the type and index by name
938+ int32_t typeLocalIndex = currentMethod->count [typeDef->dataType ] - 1 ;
939+ int32_t globalIndex = typeLocalToGlobalIndex (global, typeLocalIndex);
940+ this ->methods [methodIndex].locals .pushConstruct (name, access, typeDef, typeLocalIndex, global);
941+ return &this ->methods [methodIndex].locals .last ();
969942 } else {
970943 throwError (U" Cannot declare variable of unknown type \" " , typeName, U" \" !\n " );
971944 return nullptr ;
972945 }
973946 }
974947 }
975948
949+ void initializeVariable (int32_t methodIndex, int32_t initMethodIndex, AccessType access, const ReadableString& typeName, const ReadableString& name, bool initialize, const ReadableString& defaultValueText, bool global) {
950+ const VMTypeDef<TYPE_COUNT>* typeDef = getMachineType (typeName);
951+ Method<TYPE_COUNT>* currentMethod = &this ->methods [methodIndex];
952+ Variable<TYPE_COUNT>* variableDef = this ->getResource (name, methodIndex, initMethodIndex);
953+ if (typeDef == nullptr ) {
954+ throwError (U" Failed to find type " , typeName, U" when trying to generate machine code for initilizing " , name, U" in the virtual machine!\n " );
955+ } else if (variableDef == nullptr ) {
956+ throwError (U" Failed to find variable " , name, U" when trying to generate machine code for initilizing " , name, U" in the virtual machine!\n " );
957+ } else {
958+ int32_t typeLocalIndex = currentMethod->count [typeDef->dataType ] - 1 ;
959+ int32_t globalIndex = typeLocalToGlobalIndex (global, typeLocalIndex);
960+ this ->methods [methodIndex].locals .pushConstruct (name, access, typeDef, typeLocalIndex, global);
961+ // If the variable is supposed to be initialized automatically and no value will be given from an input, then we have to initialize it using hidden machine instructions.
962+ if (initialize && access != AccessType::Input) {
963+ // TODO: Give custom error messages when load or reset was not implemented.
964+ // If reset is missing, then the type does not have a default constructor and must have one specified.
965+ // If move is missing, then the type does not have a constructor accepting immediate constants.
966+ if (string_length (defaultValueText) > 0 ) {
967+ // An initial value was provided explicitly.
968+ // Look for a load instruction.
969+ this ->interpretCommand (methodIndex, U" Move" , List<VMA>(
970+ VMA (ArgumentType::Reference, typeDef->dataType , globalIndex),
971+ this ->interpretImmediateArgument (this ->memory .getReference (), defaultValueText)
972+ ));
973+ } else {
974+ // No initial value was provided.
975+ // Look for a reset instruction.
976+ this ->interpretCommand (methodIndex, U" Reset" , List<VMA>(
977+ VMA (ArgumentType::Reference, typeDef->dataType , globalIndex)
978+ ));
979+ }
980+ }
981+ }
982+ }
983+
976984 VMA VMAfromText (const UnresolvedProgram &unresolvedProgram, const UnresolvedMethod &unresolvedMethod, int32_t methodIndex, int32_t initMethodIndex, const ReadableString& content, bool global) {
977985 #ifdef VIRTUAL_MACHINE_DEBUG_PRINT
978986 printText (U" VMAfromText in method " , methodIndex, U" interpreting argument \" " , content, U" \" .\n " );
@@ -1029,9 +1037,9 @@ struct VirtualMachine {
10291037 }
10301038 }
10311039
1032- void generateLabelsAndStatements (int32_t methodIndex, int32_t initMethodIndex, const UnresolvedProgram &unresolvedProgram, const UnresolvedMethod &unresolvedMethod, const ReadableString& command, const List<String>& arguments, bool global) {
1040+ void generateMachineCode (int32_t methodIndex, int32_t initMethodIndex, const UnresolvedProgram &unresolvedProgram, const UnresolvedMethod &unresolvedMethod, const ReadableString& command, const List<String>& arguments, bool global) {
10331041 #ifdef VIRTUAL_MACHINE_DEBUG_PRINT
1034- printText (U" generateLabelsAndStatements @" , this ->machineWords .length (), U" in method " , methodIndex, U" " , command, U" (" );
1042+ printText (U" generateMachineCode @" , this ->machineWords .length (), U" in method " , methodIndex, U" " , command, U" (" );
10351043 for (int32_t a = 0 ; a < arguments.length (); a++) {
10361044 if (a > 0 ) { printText (U" , " ); }
10371045 printText (arguments[a]);
@@ -1042,11 +1050,14 @@ struct VirtualMachine {
10421050 throwError (U" Unexpected BEGIN command found inside of method!\n " );
10431051 } else if (string_caseInsensitiveMatch (command, U" End" )) {
10441052 throwError (U" Unexpected END command found inside of method!\n " );
1045- } else if (string_caseInsensitiveMatch (command, U" Hidden" )
1046- || string_caseInsensitiveMatch (command, U" Input" )
1047- || string_caseInsensitiveMatch (command, U" Output" )
1048- || string_caseInsensitiveMatch (command, U" Temp" )) {
1049- // Variables should already be generated.
1053+ } else if (string_caseInsensitiveMatch (command, U" Input" )) {
1054+ // No initialization needed for input.
1055+ } else if (string_caseInsensitiveMatch (command, U" Output" )) {
1056+ this ->initializeVariable (methodIndex, initMethodIndex, AccessType::Output, getArg (arguments, 0 ), getArg (arguments, 1 ), true , getArg (arguments, 2 ), global);
1057+ } else if (string_caseInsensitiveMatch (command, U" Hidden" )) {
1058+ this ->initializeVariable (methodIndex, initMethodIndex, AccessType::Hidden, getArg (arguments, 0 ), getArg (arguments, 1 ), true , getArg (arguments, 2 ), global);
1059+ } else if (string_caseInsensitiveMatch (command, U" Temp" )) {
1060+ // No initialization needed for temp.
10501061 } else if (string_caseInsensitiveMatch (command, U" Call" )) {
10511062 #ifdef VIRTUAL_MACHINE_DEBUG_PRINT
10521063 printText (U" Generating call from method " , methodIndex, U" \n " );
0 commit comments