@@ -351,13 +351,13 @@ void Generator::GenerateConstString(string label, string str)
351351
352352void Generator::GenerateStrings ()
353353{
354- if (m_source->conststrings .empty ())
355- return ;
356-
357354 AddComment (" STRINGS" );
358355 AddLine (" \t .EVEN" );
359356 AddLine (" ST0:\t .WORD\t 0\t ; empty string" );
360357
358+ if (m_source->conststrings .empty ())
359+ return ;
360+
361361 for (size_t stno = 0 ; stno < m_source->conststrings .size (); ++stno)
362362 {
363363 string strdeco = " ST" + std::to_string (stno + 1 );
@@ -652,7 +652,14 @@ void Generator::GenerateExpression(const ExpressionModel& expr, const Expression
652652
653653 if (node.vtype == ValueTypeString)
654654 {
655- AddComment (" TODO calculate string expression" );
655+ // The only operation with strings is '+'
656+ if (node.token .type == TokenTypeOperation && node.token .text == " +" && node.left >= 0 && node.right >= 0 )
657+ {
658+ GenerateOperPlus (expr, node, expr.nodes [node.left ], expr.nodes [node.right ]);
659+ return ;
660+ }
661+
662+ assert (false ); // should not fall in here
656663 return ;
657664 }
658665
@@ -784,24 +791,24 @@ void Generator::GenerateAssignment(VariableExpressionModel& var, ExpressionModel
784791 ValueType vtype = var.GetValueType ();
785792 string canoname = var.GetVariableCanonicName ();
786793 string deconame = var.GetVariableDecoratedName ();
794+ ValueType exprvtype = expr.GetExpressionValueType ();
787795
788796 const string comment = " \t ; var " + canoname + " assignment" ;
789797
790798 if (expr.IsConstExpression ())
791799 {
792- if (vtype == ValueTypeInteger && expr. GetExpressionValueType () == ValueTypeInteger)
800+ if (vtype == ValueTypeInteger && (exprvtype == ValueTypeInteger || exprvtype == ValueTypeSingle) )
793801 {
794802 int ivalue = (int )std::floor (expr.GetConstExpressionDValue ());
795803 if (ivalue == 0 )
796- {
797804 AddLine (" \t CLR\t " + deconame + comment);
798- }
799805 else {
800806 string svalue = " #" + std::to_string (ivalue) + " ." ;
801807 AddLine (" \t MOV\t " + svalue + " , " + deconame + comment);
802808 }
809+ return ;
803810 }
804- else if (vtype == ValueTypeSingle && expr. GetExpressionValueType () == ValueTypeSingle) // const Single
811+ if (vtype == ValueTypeSingle && (exprvtype == ValueTypeInteger || exprvtype == ValueTypeSingle))
805812 {
806813 float fvalue = static_cast <float >(expr.GetConstExpressionDValue ());
807814 string comment = " \t ; var " + canoname + " = const " + to_string_float (static_cast <float >(expr.GetConstExpressionDValue ()));
@@ -810,73 +817,87 @@ void Generator::GenerateAssignment(VariableExpressionModel& var, ExpressionModel
810817 uint16_t wordhi = bits >> 16 ;
811818 AddLine ((wordlo == 0 ? " \t CLR\t " : " \t MOV\t #" + to_string_octal (wordlo) + " , " ) + deconame + comment);
812819 AddLine ((wordhi == 0 ? " \t CLR\t " : " \t MOV\t #" + to_string_octal (wordhi) + " , " ) + deconame + " +2" );
820+ return ;
813821 }
814- else if (vtype == ValueTypeString) // const String
822+ if (vtype == ValueTypeString) // const String
815823 {
816824 string svalue = expr.GetConstExpressionSValue ();
825+ if (svalue == " " ) // Special case for empty string
826+ {
827+ AddLine (" \t CLR\t " + deconame + " \t ; var " + canoname + " assignment" );
828+ return ;
829+ }
830+ if (svalue.size () == 1 ) // Special case for one-char string
831+ {
832+ // NOTE: Character conversion depends on encoding
833+ uint16_t value = (1 << 8 ) | svalue[0 ];
834+ AddLine (" \t MOV\t #" + to_string_octal (value) + " , " + deconame + " \t ; var " + canoname + " assignment" );
835+ return ;
836+ }
817837 int sindex = m_source->GetConstStringIndex (svalue);
818- // TODO: Special case for one-char string
819838 AddLine (" \t MOV\t #ST" + std::to_string (sindex) + " , R0" );
820839 AddLine (" \t MOV\t #" + deconame + " , R1" );
821840 AddRuntimeCall (RuntimeSTCP, " var " + canoname + " assignment" );
841+ return ;
822842 }
823843 }
824- else if (expr.IsVariableExpression () && expr.GetExpressionValueType () == ValueTypeInteger && vtype == ValueTypeInteger)
844+
845+ if (expr.IsVariableExpression () && exprvtype == ValueTypeInteger && vtype == ValueTypeInteger)
825846 {
826847 string svalue = expr.GetVariableExpressionDecoratedName ();
827848 AddLine (" \t MOV\t " + svalue + " , " + deconame + comment);
849+ return ;
828850 }
829- else if (expr.IsVariableExpression () && expr. GetExpressionValueType () == ValueTypeSingle && vtype == ValueTypeSingle)
851+ if (expr.IsVariableExpression () && exprvtype == ValueTypeSingle && vtype == ValueTypeSingle)
830852 {
831853 string svalue = expr.GetVariableExpressionDecoratedName ();
832854 AddLine (" \t MOV\t " + svalue + " , " + deconame + comment);
833855 AddLine (" \t MOV\t " + svalue + " +2, " + deconame + " +2" );
856+ return ;
834857 }
835- // TODO: String var = String var
836- else // non-const, non-variable
858+
859+ // non-const, non-variable
860+ ExpressionNode& root = expr.nodes [expr.root ];
861+
862+ // Convert "A% = A% + N" and "A% = A% - N" assignments into INC/DEC/ADD/SUB
863+ if (vtype == ValueTypeInteger && root.token .IsBinaryOperation () &&
864+ (root.token .text == " -" || root.token .text == " +" ) &&
865+ expr.nodes [root.left ].token .type == TokenTypeIdentifier &&
866+ GetCanonicVariableName (expr.nodes [root.left ].token .text ) == var.name &&
867+ expr.nodes [root.right ].constval &&
868+ (expr.nodes [root.right ].vtype == ValueTypeInteger || expr.nodes [root.right ].vtype == ValueTypeSingle))
869+ {
870+ bool plusminus = (root.token .text == " +" );
871+ int ivalue = (int )std::floor (expr.nodes [root.right ].token .dvalue );
872+ if (plusminus && ivalue == 1 )
873+ AddLine (" \t INC\t " + deconame + comment);
874+ else if (!plusminus && ivalue == 1 )
875+ AddLine (" \t DEC\t " + deconame + comment);
876+ else if (plusminus && ivalue != 1 )
877+ AddLine (" \t ADD\t #" + std::to_string (ivalue) + " ., " + deconame + comment);
878+ else // if (!plusminus && ivalue != 1)
879+ AddLine (" \t SUB\t #" + std::to_string (ivalue) + " ., " + deconame + comment);
880+ }
881+ else if (vtype == ValueTypeSingle) // non-const Single
882+ {
883+ GenerateExpression (expr);
884+ if (exprvtype == ValueTypeInteger)
885+ AddRuntimeCall (RuntimeITOF, " to Single" ); // result on stack
886+ AddLine (" \t MOV\t (SP)+, " + deconame + " +2" + comment);
887+ AddLine (" \t MOV\t (SP)+, " + deconame);
888+ }
889+ else if (vtype == ValueTypeInteger) // non-const non-variable Integer
837890 {
838- ExpressionNode& root = expr.nodes [expr.root ];
839-
840- // Convert "A% = A% + N" and "A% = A% - N" assignments into INC/DEC/ADD/SUB
841- if (vtype == ValueTypeInteger && root.token .IsBinaryOperation () &&
842- (root.token .text == " -" || root.token .text == " +" ) &&
843- expr.nodes [root.left ].token .type == TokenTypeIdentifier &&
844- GetCanonicVariableName (expr.nodes [root.left ].token .text ) == var.name &&
845- expr.nodes [root.right ].constval &&
846- (expr.nodes [root.right ].vtype == ValueTypeInteger || expr.nodes [root.right ].vtype == ValueTypeSingle))
847- {
848- bool plusminus = (root.token .text == " +" );
849- int ivalue = (int )std::floor (expr.nodes [root.right ].token .dvalue );
850- if (plusminus && ivalue == 1 )
851- AddLine (" \t INC\t " + deconame + comment);
852- else if (!plusminus && ivalue == 1 )
853- AddLine (" \t DEC\t " + deconame + comment);
854- else if (plusminus && ivalue != 1 )
855- AddLine (" \t ADD\t #" + std::to_string (ivalue) + " ., " + deconame + comment);
856- else // if (!plusminus && ivalue != 1)
857- AddLine (" \t SUB\t #" + std::to_string (ivalue) + " ., " + deconame + comment);
858- }
859- else if (vtype == ValueTypeSingle) // non-const Single
860- {
861- GenerateExpression (expr);
862- if (expr.GetExpressionValueType () == ValueTypeInteger)
863- AddRuntimeCall (RuntimeITOF, " to Single" ); // result on stack
864- AddLine (" \t MOV\t (SP)+, " + deconame + " +2" + comment);
865- AddLine (" \t MOV\t (SP)+, " + deconame);
866- }
867- else if (vtype == ValueTypeInteger) // non-const non-variable Integer
868- {
869- GenerateExpression (expr);
870- if (expr.GetExpressionValueType () == ValueTypeSingle)
871- AddRuntimeCall (RuntimeFTOI, " to Integer" ); // result in R0
872- AddLine (" \t MOV\t R0, " + deconame + comment);
873- }
874- else // non-const non-variable String
875- {
876- GenerateExpression (expr);
877- AddLine (" \t MOV\t " + deconame + " , R1" );
878- AddRuntimeCall (RuntimeSTCP, " var " + canoname + " assignment" );
879- }
891+ GenerateExpression (expr);
892+ if (exprvtype == ValueTypeSingle)
893+ AddRuntimeCall (RuntimeFTOI, " to Integer" ); // result in R0
894+ AddLine (" \t MOV\t R0, " + deconame + comment);
895+ }
896+ else // non-const non-variable String
897+ {
898+ GenerateExpression (expr);
899+ AddLine (" \t MOV\t " + deconame + " , R1" );
900+ AddRuntimeCall (RuntimeSTCP, " var " + canoname + " assignment" );
880901 }
881902}
882903
@@ -1928,9 +1949,30 @@ void Generator::GenerateOperPlus(const ExpressionModel& expr, const ExpressionNo
19281949{
19291950 const string comment = " \t ; Operation \' +\' " ;
19301951
1931- // String operands
1952+ // String + String
19321953 if (nodeleft.vtype == ValueTypeString && noderight.vtype == ValueTypeString)
19331954 {
1955+ if (nodeleft.constval && nodeleft.GetConstStringValue () == " " )
1956+ {
1957+ Warning (node.token , " Concatenation with empty string at left; consider to remove the useless concatenation." );
1958+ GenerateExpression (expr, noderight);
1959+ return ;
1960+ }
1961+
1962+ if (noderight.constval )
1963+ {
1964+ if (noderight.GetConstStringValue () == " " )
1965+ {
1966+ Warning (node.token , " Concatenation with empty string at right; consider to remove the useless concatenation." );
1967+ GenerateExpression (expr, nodeleft);
1968+ return ;
1969+ }
1970+
1971+ // TODO
1972+ }
1973+
1974+ // TODO
1975+ AddRuntimeCall (RuntimeSSAL, " allocate string" );
19341976 // TODO
19351977 AddComment (" TODO String + String" );
19361978 return ;
@@ -1939,7 +1981,7 @@ void Generator::GenerateOperPlus(const ExpressionModel& expr, const ExpressionNo
19391981 assert (nodeleft.vtype != ValueTypeString);
19401982 assert (noderight.vtype != ValueTypeString);
19411983
1942- // Single operands
1984+ // Single operands, result is Single
19431985 if (nodeleft.vtype == ValueTypeSingle || noderight.vtype == ValueTypeSingle)
19441986 {
19451987 GenerateExpression (expr, nodeleft);
@@ -1954,6 +1996,9 @@ void Generator::GenerateOperPlus(const ExpressionModel& expr, const ExpressionNo
19541996 return ;
19551997 }
19561998
1999+ assert (nodeleft.vtype == ValueTypeInteger);
2000+ assert (noderight.vtype == ValueTypeInteger);
2001+
19572002 GenerateExpression (expr, nodeleft); // result in R0
19582003
19592004 // Convert "XXX + N" into INC/ADD
@@ -2368,7 +2413,6 @@ void Generator::GenerateLogicOperArguments(const ExpressionModel& expr, const Ex
23682413 }
23692414 else
23702415 {
2371- // TODO: Special cases "String equals empty String" and "String not equals empty String"
23722416 assert (noderight.vtype == ValueTypeString);
23732417 AddRuntimeCall (RuntimeSTCM);
23742418 AddComment (" TODO compare String to String" );
@@ -2379,19 +2423,64 @@ void Generator::GenerateLogicOperArguments(const ExpressionModel& expr, const Ex
23792423
23802424void Generator::GenerateOperEqual (const ExpressionModel& expr, const ExpressionNode& node, const ExpressionNode& nodeleft, const ExpressionNode& noderight)
23812425{
2382- const string comment = " \t ; Operation \' =\' " ;
2383-
2384- GenerateLogicOperArguments (expr, nodeleft, noderight);
2426+ // Special case: String equals empty String
2427+ if (nodeleft.vtype == ValueTypeString && noderight.vtype == ValueTypeString &&
2428+ noderight.constval && noderight.GetConstStringValue () == " " )
2429+ {
2430+ GenerateExpression (expr, nodeleft); // result in R0
2431+ AddLine (" \t TSTB\t (R0)" );
2432+ }
2433+ // Special case: empty String equals String
2434+ else if (nodeleft.vtype == ValueTypeString && noderight.vtype == ValueTypeString &&
2435+ nodeleft.constval && nodeleft.GetConstStringValue () == " " )
2436+ {
2437+ GenerateExpression (expr, noderight); // result in R0
2438+ AddLine (" \t TSTB\t (R0)" );
2439+ }
2440+ // Special case: String equals one-char String
2441+ else if (nodeleft.vtype == ValueTypeString && noderight.vtype == ValueTypeString &&
2442+ noderight.constval && noderight.GetConstStringValue ().size () == 1 )
2443+ {
2444+ GenerateExpression (expr, nodeleft); // result in R0
2445+ string svalue = noderight.GetConstStringValue ();
2446+ // NOTE: Character conversion depends on encoding
2447+ uint16_t value = (1 << 8 ) | svalue[0 ];
2448+ AddLine (" \t CMP\t (R0), #" + to_string_octal (value));
2449+ }
2450+ else // all other cases
2451+ {
2452+ GenerateLogicOperArguments (expr, nodeleft, noderight);
2453+ }
23852454
2386- AddLine (" \t BEQ\t .+6" );
2455+ AddLine (" \t BEQ\t .+6\t ; Operation \' = \' " );
23872456 AddLine (" \t CLR\t R0\t ; false" );
23882457 AddLine (" \t BR\t .+6" );
23892458 AddLine (" \t MOV\t #-1, R0\t ; true" );
23902459}
23912460
23922461void Generator::GenerateOperNotEqual (const ExpressionModel& expr, const ExpressionNode& node, const ExpressionNode& nodeleft, const ExpressionNode& noderight)
23932462{
2394- GenerateLogicOperArguments (expr, nodeleft, noderight);
2463+ // Special case: String <> empty String
2464+ if (nodeleft.vtype == ValueTypeString && noderight.vtype == ValueTypeString &&
2465+ noderight.constval && noderight.GetConstStringValue () == " " )
2466+ {
2467+ GenerateExpression (expr, nodeleft); // result in R0
2468+ AddLine (" \t TSTB\t (R0)" );
2469+ }
2470+ // Special case: empty String <> String
2471+ else if (nodeleft.vtype == ValueTypeString && noderight.vtype == ValueTypeString &&
2472+ nodeleft.constval && nodeleft.GetConstStringValue () == " " )
2473+ {
2474+ GenerateExpression (expr, noderight); // result in R0
2475+ AddLine (" \t TSTB\t (R0)" );
2476+ }
2477+ // TODO Special case: String <> 1-char String
2478+
2479+ // all other cases
2480+ else
2481+ {
2482+ GenerateLogicOperArguments (expr, nodeleft, noderight);
2483+ }
23952484
23962485 AddLine (" \t BNE\t .+6\t ; Operation \' <>\' " );
23972486 AddLine (" \t CLR\t R0\t ; false" );
0 commit comments