Skip to content

Commit 2a4698f

Browse files
committed
WIP string expressions
1 parent 50dc48c commit 2a4698f

18 files changed

Lines changed: 312 additions & 144 deletions

generator.cpp

Lines changed: 153 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -351,13 +351,13 @@ void Generator::GenerateConstString(string label, string str)
351351

352352
void Generator::GenerateStrings()
353353
{
354-
if (m_source->conststrings.empty())
355-
return;
356-
357354
AddComment("STRINGS");
358355
AddLine("\t.EVEN");
359356
AddLine("ST0:\t.WORD\t0\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("\tCLR\t" + deconame + comment);
798-
}
799805
else {
800806
string svalue = "#" + std::to_string(ivalue) + ".";
801807
AddLine("\tMOV\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 ? "\tCLR\t" : "\tMOV\t#" + to_string_octal(wordlo) + ", ") + deconame + comment);
812819
AddLine((wordhi == 0 ? "\tCLR\t" : "\tMOV\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("\tCLR\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("\tMOV\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("\tMOV\t#ST" + std::to_string(sindex) + ", R0");
820839
AddLine("\tMOV\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("\tMOV\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("\tMOV\t" + svalue + ", " + deconame + comment);
833855
AddLine("\tMOV\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("\tINC\t" + deconame + comment);
874+
else if (!plusminus && ivalue == 1)
875+
AddLine("\tDEC\t" + deconame + comment);
876+
else if (plusminus && ivalue != 1)
877+
AddLine("\tADD\t#" + std::to_string(ivalue) + "., " + deconame + comment);
878+
else //if (!plusminus && ivalue != 1)
879+
AddLine("\tSUB\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("\tMOV\t(SP)+, " + deconame + "+2" + comment);
887+
AddLine("\tMOV\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("\tINC\t" + deconame + comment);
852-
else if (!plusminus && ivalue == 1)
853-
AddLine("\tDEC\t" + deconame + comment);
854-
else if (plusminus && ivalue != 1)
855-
AddLine("\tADD\t#" + std::to_string(ivalue) + "., " + deconame + comment);
856-
else //if (!plusminus && ivalue != 1)
857-
AddLine("\tSUB\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("\tMOV\t(SP)+, " + deconame + "+2" + comment);
865-
AddLine("\tMOV\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("\tMOV\tR0, " + deconame + comment);
873-
}
874-
else // non-const non-variable String
875-
{
876-
GenerateExpression(expr);
877-
AddLine("\tMOV\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("\tMOV\tR0, " + deconame + comment);
895+
}
896+
else // non-const non-variable String
897+
{
898+
GenerateExpression(expr);
899+
AddLine("\tMOV\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

23802424
void 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("\tTSTB\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("\tTSTB\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("\tCMP\t(R0), #" + to_string_octal(value));
2449+
}
2450+
else // all other cases
2451+
{
2452+
GenerateLogicOperArguments(expr, nodeleft, noderight);
2453+
}
23852454

2386-
AddLine("\tBEQ\t.+6");
2455+
AddLine("\tBEQ\t.+6\t; Operation \'=\'");
23872456
AddLine("\tCLR\tR0\t; false");
23882457
AddLine("\tBR\t.+6");
23892458
AddLine("\tMOV\t#-1, R0\t; true");
23902459
}
23912460

23922461
void 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("\tTSTB\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("\tTSTB\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("\tBNE\t.+6\t; Operation \'<>\'");
23972486
AddLine("\tCLR\tR0\t; false");

main.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ enum RuntimeSymbol
162162
RuntimeINKEY = 49, // INKEY$ function
163163
RuntimeSTCP = 50, // String copy
164164
RuntimeSTCM = 51, // Compare two Strings
165-
RuntimeCOLR = 52, // COLOR
165+
RuntimeSSAL = 52, // String Stack allocate
166+
RuntimeReserved6 = 53,
167+
RuntimeCOLR = 54, // COLOR
166168
__RuntimeSymbol_SIZE__
167169
};
168170

@@ -275,6 +277,7 @@ struct ExpressionNode
275277
void Dump(std::ostream& out) const;
276278
string GetNodeVTypeStr() const;
277279
int GetConstIntegerValue() const;
280+
string GetConstStringValue() const;
278281
};
279282

280283
struct ExpressionModel

model.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@ int ExpressionNode::GetConstIntegerValue() const
296296
return ivalue;
297297
}
298298

299+
string ExpressionNode::GetConstStringValue() const
300+
{
301+
assert(constval);
302+
return token.svalue;
303+
}
304+
299305

300306
//////////////////////////////////////////////////////////////////////
301307
// ExpressionModel
@@ -592,6 +598,8 @@ const char* RuntimeSymbolNames[] = {
592598
"REST", "REAI", "REAF", "REAS",
593599
"INKEY",
594600
"STCP", "STCM",
601+
"SSAL",
602+
"", // Reserved
595603
"COLR",
596604
};
597605

0 commit comments

Comments
 (0)