Skip to content

Commit e533d6b

Browse files
committed
FOR..NEXT linked by forindex, not line number
1 parent bd0b689 commit e533d6b

7 files changed

Lines changed: 106 additions & 85 deletions

File tree

generator.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,8 @@ void Generator::GenerateFor(StatementModel& statement)
905905
ExpressionModel& expr1 = statement.args[0];
906906
assert(expr1.GetExpressionValueType() != ValueTypeString);
907907

908+
assert(statement.forindex != 0);
909+
908910
assert(statement.ident.type == TokenTypeIdentifier);
909911
VariableExpressionModel var;
910912
var.name = statement.ident.text;
@@ -925,14 +927,14 @@ void Generator::GenerateFor(StatementModel& statement)
925927
{
926928
//TODO: register variable
927929
string svalue = expr2.GetVariableExpressionDecoratedName();
928-
AddLine("\tMOV\t" + svalue + ", @#<R" + std::to_string(m_line->linenum) + "+2>");
930+
AddLine("\tMOV\t" + svalue + ", @#<F" + std::to_string(statement.forindex) + "+2>");
929931
}
930932
else
931933
{
932934
GenerateExpression(expr2);
933935
if (expr2.GetExpressionValueType() == ValueTypeSingle)
934936
AddRuntimeCall(RuntimeFTOI, "to Integer"); // result in R0
935-
AddLine("\tMOV\tR0, @#<R" + std::to_string(m_line->linenum) + "+2>"); // Save "to" value
937+
AddLine("\tMOV\tR0, @#<F" + std::to_string(statement.forindex) + "+2>"); // Save "to" value
936938
}
937939

938940
if (statement.args.size() > 2) // has STEP expression
@@ -948,14 +950,13 @@ void Generator::GenerateFor(StatementModel& statement)
948950
if (expr3.GetExpressionValueType() == ValueTypeSingle)
949951
AddRuntimeCall(RuntimeFTOI, "to Integer"); // result in R0
950952
// Save "step" value
951-
AddLine("\tMOV\tR0, @#<S" + std::to_string(m_line->linenum) + "+2>");
953+
AddLine("\tMOV\tR0, @#<S" + std::to_string(statement.forindex) + "+2>");
952954
}
953955
}
954956

955-
string nextlinelabel = m_source->GetNextLineLabel(m_line->linenum);
956-
AddLine("R" + std::to_string(m_line->linenum) + ":\tCMP\t" + tovalue + ", " + deconame);
957+
AddLine("F" + std::to_string(statement.forindex) + ":\tCMP\t" + tovalue + ", " + deconame);
957958
AddLine("\tBGE\t.+6\t; to loop body");
958-
AddLine("\tJMP\tX" + std::to_string(m_line->linenum)); // label after NEXT
959+
AddLine("\tJMP\tX" + std::to_string(statement.forindex)); // label after NEXT
959960
}
960961

961962
// NEXT [<ПАРАМЕТР>[,< ПАРАМЕТР >...]]
@@ -968,11 +969,10 @@ void Generator::GenerateNext(StatementModel& statement)
968969
SourceLineModel* plinefor = variable.psourceline;
969970
assert(plinefor != nullptr);
970971
StatementModel& forstatement = plinefor->statement;
972+
assert(forstatement.forindex != 0);
971973

972974
string canoname = variable.GetVariableCanonicName();
973975
string deconame = DecorateVariableName(canoname);
974-
int forlinenum = plinefor->linenum;
975-
assert(forlinenum > 0);
976976
string comment = "NEXT " + canoname;
977977

978978
// Increment FOR variable by 1 or by STEP value
@@ -991,14 +991,14 @@ void Generator::GenerateNext(StatementModel& statement)
991991
else
992992
{
993993
//NOTE: "#1" here will be replaced at run-time with calculated STEP value
994-
AddLine("S" + std::to_string(forlinenum) + ":\tADD\t#1, " + deconame + "\t; " + comment);
994+
AddLine("S" + std::to_string(forstatement.forindex) + ":\tADD\t#1, " + deconame + "\t; " + comment);
995995
}
996996
}
997997

998998
// JMP to continue loop
999-
AddLine("\tJMP\tR" + std::to_string(forlinenum) + "\t; continue loop");
999+
AddLine("\tJMP\tF" + std::to_string(forstatement.forindex) + "\t; continue loop");
10001000
// Label after NEXT
1001-
AddLine("X" + std::to_string(forlinenum) + ":\t; FOR exit addr");
1001+
AddLine("X" + std::to_string(forstatement.forindex) + ":\t; FOR exit addr");
10021002
}
10031003
}
10041004

main.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ struct StatementModel
301301
bool gotogosub; // true for ON GOTO, false for ON GOSUB
302302
bool deffnorusr; // true for DEF FN, false for DEF USR
303303
bool nocrlf; // PRINT flag indicating we don't need CR/LF at the end
304+
int forindex; // Index used to tie FOR..NEXT parts together
304305
FileMode filemode; // File mode for OPEN
305306
std::vector<ExpressionModel> args; // Statement arguments
306307
std::vector<Token> params; // Statement params like list of variables
@@ -339,7 +340,7 @@ struct SourceModel
339340
bool IsVariableRegistered(const string& varname) const;
340341
bool IsLineNumberExists(int linenumber) const;
341342
string GetNextLineLabel(int linenumber) const;
342-
SourceLineModel& GetSourceLine(int linenumber);
343+
SourceLineModel& GetSourceLine(int srclinenumber);
343344
void RegisterConstString(const string& str);
344345
int GetConstStringIndex(const string& str);
345346
};
@@ -494,7 +495,7 @@ struct ValidatorFuncSpec
494495

495496
struct ValidatorForSpec
496497
{
497-
int linenum; // FOR statement line number
498+
int srclinenum; // FOR statement source line number
498499
string varname;
499500
};
500501

@@ -504,6 +505,7 @@ class Validator
504505
int m_lineindex;
505506
SourceLineModel* m_line; // Curent line being validated
506507
std::vector<ValidatorForSpec> m_fornextstack;
508+
int m_forcount;
507509
private:
508510
static const ValidatorKeywordSpec m_keywordspecs[];
509511
static const ValidatorOperSpec m_operspecs[];
@@ -512,6 +514,7 @@ class Validator
512514
Validator(SourceModel* source);
513515
public:
514516
bool ProcessLine();
517+
void ProcessEnd();
515518
private:
516519
void ValidateStatement(StatementModel& statement);
517520
void Error(const string& message);

model.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,17 +487,17 @@ string SourceModel::GetNextLineLabel(int linenumber) const
487487
return "LEND";
488488
}
489489

490-
SourceLineModel& SourceModel::GetSourceLine(int linenumber)
490+
SourceLineModel& SourceModel::GetSourceLine(int srclinenumber)
491491
{
492-
assert(linenumber < MAX_LINE_NUMBER);
492+
assert(srclinenumber > 0);
493493

494494
for (auto it = std::begin(lines); it != std::end(lines); ++it)
495495
{
496-
if (it->linenum == linenumber)
496+
if (it->srclinenum == srclinenumber)
497497
return *it;
498498
}
499499

500-
assert(false); // Line number not found
500+
assert(false); // Line not found
501501
exit(EXIT_FAILURE);
502502
}
503503

runtime-BK0010.tmac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,6 @@ FADD$X = .
13481348
CLR R1
13491349
12$: CLR R3
13501350
BR 13$
1351-
13521351
;
13531352
; Ошибка: переполнение
13541353
FADD$O: MOV FADD$X+2, R5 ; откуда вызвали
@@ -1363,6 +1362,7 @@ FADD$O: MOV FADD$X+2, R5 ;
13631362
; (SP+2)(SP+4) - плавающее число B (старшее, младшее слово)
13641363
; (SP+6)(SP+10) - плавающее число A (старшее, младшее слово)
13651364
; Результат: (SP)(SP+2) - плавающее число (старшее слово, младшее слово)
1365+
; Портит регистры: те же что FADD
13661366
FSUB:
13671367
TST 2(SP) ; проверяем старше слово B
13681368
BEQ 1$ ; ноль =>
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
-q
22
----------------------------------------------------------------------
3+
FOR J% = 1% TO 10%
34
FOR I% = 1% TO 10%
4-
NEXT
5+
NEXT I%
56
----------------------------------------------------------------------
6-
ERROR at 1 - Line with FOR statement should have line number.
7+
ERROR at 1 - FOR statement has no corresponding NEXT.
78
Validation ERRORS: 1

tests/0110-sin-cos.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-q
2+
----------------------------------------------------------------------
3+
10 FOR I% = -10 TO 10
4+
A = PI * I% / 4
5+
? A, SIN(A), COS(A)
6+
NEXT I%

validator.cpp

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ Validator::Validator(SourceModel* source)
130130

131131
m_lineindex = -1;
132132
m_line = nullptr;
133+
134+
m_forcount = 0;
133135
}
134136

135137
bool Validator::ProcessLine()
@@ -144,24 +146,30 @@ bool Validator::ProcessLine()
144146

145147
if (m_lineindex >= (int)m_source->lines.size())
146148
{
147-
//ProcessEnd();
149+
ProcessEnd();
148150
m_lineindex = INT_MAX;
149151
return false;
150152
}
151153

152154
m_line = &(m_source->lines[m_lineindex]);
153155

154-
// Spectial case: line with FOR statement should have line number
155-
if (m_line->linenum == 0 && m_line->statement.token.keyword == KeywordFOR)
156-
{
157-
Error("Line with FOR statement should have line number.");
158-
}
159-
160156
ValidateStatement(m_line->statement);
161157

162158
return true;
163159
}
164160

161+
void Validator::ProcessEnd()
162+
{
163+
if (!m_fornextstack.empty())
164+
{
165+
const ValidatorForSpec& forspec = m_fornextstack.back();
166+
167+
std::cerr << "ERROR at " << forspec.srclinenum << " - FOR statement has no corresponding NEXT." << std::endl;
168+
m_line->error = true;
169+
RegisterError();
170+
}
171+
}
172+
165173
void Validator::ValidateStatement(StatementModel& statement)
166174
{
167175
// Find validator implementation
@@ -527,11 +535,14 @@ void Validator::ValidateFor(StatementModel& statement)
527535
//TODO: check variable type
528536

529537
// Add FOR variable to FOR/NEXT stack
538+
m_forcount++;
530539
ValidatorForSpec forspec;
531540
forspec.varname = var.name;
532-
forspec.linenum = m_line->linenum;
541+
forspec.srclinenum = m_line->srclinenum;
533542
m_fornextstack.push_back(forspec);
534543

544+
statement.forindex = m_forcount;
545+
535546
if (statement.args.size() < 2)
536547
MODEL_ERROR("Two parameters expected.");
537548

@@ -554,6 +565,63 @@ void Validator::ValidateFor(StatementModel& statement)
554565
}
555566
}
556567

568+
// NEXT [<ПАРАМЕТР>[,< ПАРАМЕТР >...]]
569+
void Validator::ValidateNext(StatementModel& statement)
570+
{
571+
//NOTE: Filling statement.variables with list of NEXT variables plus link to FOR statement for each
572+
573+
if (statement.params.empty()) // NEXT without parameters
574+
{
575+
if (m_fornextstack.empty())
576+
MODEL_ERROR("NEXT without FOR.");
577+
578+
ValidatorForSpec forspec = m_fornextstack.back();
579+
m_fornextstack.pop_back();
580+
581+
Token tokenvar;
582+
tokenvar.type = TokenTypeIdentifier;
583+
tokenvar.text = forspec.varname;
584+
statement.params.push_back(tokenvar);
585+
586+
// link FOR to the NEXT line number
587+
SourceLineModel& linefor = m_source->GetSourceLine(forspec.srclinenum);
588+
assert(linefor.statement.forindex != 0);
589+
590+
VariableModel variable;
591+
variable.name = forspec.varname;
592+
variable.psourceline = &linefor;
593+
statement.variables.push_back(variable);
594+
595+
return;
596+
}
597+
598+
for (auto it = std::begin(statement.params); it != std::end(statement.params); ++it)
599+
{
600+
if (m_fornextstack.empty())
601+
MODEL_ERROR("NEXT without FOR.");
602+
603+
ValidatorForSpec forspec = m_fornextstack.back();
604+
605+
string varname = GetCanonicVariableName(it->text);
606+
if (forspec.varname != varname)
607+
MODEL_ERROR("NEXT variable expected: " + forspec.varname + ", found: " + varname + ".");
608+
assert(m_source->IsVariableRegistered(varname));
609+
610+
//TODO: Check for numeric variable type?
611+
612+
m_fornextstack.pop_back();
613+
614+
// link FOR to the NEXT line number
615+
SourceLineModel& linefor = m_source->GetSourceLine(forspec.srclinenum);
616+
assert(linefor.statement.forindex != 0);
617+
618+
VariableModel variable;
619+
variable.name = varname;
620+
variable.psourceline = &linefor;
621+
statement.variables.push_back(variable);
622+
}
623+
}
624+
557625
void Validator::ValidateGotoGosub(StatementModel& statement)
558626
{
559627
if (!m_source->IsLineNumberExists(statement.paramline))
@@ -884,63 +952,6 @@ void Validator::ValidatePsetPreset(StatementModel& statement)
884952
MODEL_ERROR("Too many parameters.");
885953
}
886954

887-
// NEXT [<ПАРАМЕТР>[,< ПАРАМЕТР >...]]
888-
void Validator::ValidateNext(StatementModel& statement)
889-
{
890-
//NOTE: Filling statement.variables with list of NEXT variables plus link to FOR statement for each
891-
892-
if (statement.params.empty()) // NEXT without parameters
893-
{
894-
if (m_fornextstack.empty())
895-
MODEL_ERROR("NEXT without FOR.");
896-
897-
ValidatorForSpec forspec = m_fornextstack.back();
898-
m_fornextstack.pop_back();
899-
900-
Token tokenvar;
901-
tokenvar.type = TokenTypeIdentifier;
902-
tokenvar.text = forspec.varname;
903-
statement.params.push_back(tokenvar);
904-
905-
// link FOR to the NEXT line number
906-
SourceLineModel& linefor = m_source->GetSourceLine(forspec.linenum);
907-
linefor.statement.paramline = m_line->linenum;
908-
909-
VariableModel variable;
910-
variable.name = forspec.varname;
911-
variable.psourceline = &linefor;
912-
statement.variables.push_back(variable);
913-
914-
return;
915-
}
916-
917-
for (auto it = std::begin(statement.params); it != std::end(statement.params); ++it)
918-
{
919-
if (m_fornextstack.empty())
920-
MODEL_ERROR("NEXT without FOR.");
921-
922-
ValidatorForSpec forspec = m_fornextstack.back();
923-
924-
string varname = GetCanonicVariableName(it->text);
925-
if (forspec.varname != varname)
926-
MODEL_ERROR("NEXT variable expected: " + forspec.varname + ", found: " + varname + ".");
927-
assert(m_source->IsVariableRegistered(varname));
928-
929-
//TODO: Check for numeric variable type?
930-
931-
m_fornextstack.pop_back();
932-
933-
// link FOR to the NEXT line number
934-
SourceLineModel& linefor = m_source->GetSourceLine(forspec.linenum);
935-
linefor.statement.paramline = m_line->linenum;
936-
937-
VariableModel variable;
938-
variable.name = varname;
939-
variable.psourceline = &linefor;
940-
statement.variables.push_back(variable);
941-
}
942-
}
943-
944955
// ON <ВЫРАЖЕНИЕ> GOTO <СПИСОК>
945956
// ON <ВЫРАЖЕНИЕ> GOSUB <СПИСОК>
946957
void Validator::ValidateOn(StatementModel& statement)

0 commit comments

Comments
 (0)