Skip to content

Commit b009dfa

Browse files
committed
DATA/READ/RESTORE
1 parent 3a97d98 commit b009dfa

15 files changed

Lines changed: 655 additions & 137 deletions

generator.cpp

Lines changed: 226 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ void Generator::ProcessEnd()
272272

273273
GenerateVariables();
274274

275+
GenerateDataBlock();
276+
275277
GenerateRuntimeNeeds();
276278

277279
//NOTE: .END instruction will be generated in main.cpp
@@ -292,6 +294,60 @@ void Generator::ProcessEnd()
292294
}
293295
}
294296

297+
void Generator::GenerateConstString(string label, string str)
298+
{
299+
string strlen = std::to_string(str.length());
300+
if (str.length() > 7) strlen += '.';
301+
if (str.length() % 2 == 0) str += '\0'; // to align strings to word boundary
302+
// Mask special symbols, mask '/'
303+
std::ostringstream oss;
304+
if (!label.empty())
305+
oss << label << ":";
306+
oss << "\t.ASCII\t<" << strlen << ">";
307+
bool mode = false; // false = out of brackets, true = inside brackets
308+
for (size_t i = 0; i < str.length(); i++)
309+
{
310+
char ch = str[i];
311+
if ((ch >= 0 && ch < 32) || ch == '/')
312+
{
313+
if (mode)
314+
{
315+
oss << "/";
316+
mode = false;
317+
}
318+
oss << "<" << std::oct << (unsigned int)ch << ">";
319+
}
320+
else
321+
{
322+
if (!mode)
323+
{
324+
oss << "/";
325+
mode = true;
326+
}
327+
oss << ch;
328+
}
329+
if (oss.tellp() >= 93 - 6)
330+
{
331+
if (mode)
332+
{
333+
oss << "/";
334+
mode = false;
335+
}
336+
AddLine(oss.str());
337+
oss.str("");
338+
oss.clear();
339+
if (i < str.length() - 1)
340+
oss << "\t.ASCII\t";
341+
}
342+
}
343+
if (oss.tellp() > 0)
344+
{
345+
if (mode)
346+
oss << "/";
347+
AddLine(oss.str());
348+
}
349+
}
350+
295351
void Generator::GenerateStrings()
296352
{
297353
if (m_source->conststrings.empty())
@@ -305,54 +361,7 @@ void Generator::GenerateStrings()
305361
{
306362
string strdeco = "ST" + std::to_string(stno + 1);
307363
string& str = m_source->conststrings[stno];
308-
string strlen = std::to_string(str.length());
309-
if (str.length() > 7) strlen += '.';
310-
if (str.length() % 2 == 0) str += '\0'; // to align strings to word boundary
311-
// Mask special symbols, mask '/'
312-
std::ostringstream oss;
313-
oss << strdeco << ":\t.ASCII\t<" << strlen << ">";
314-
bool mode = false; // false = out of brackets, true = inside brackets
315-
for (size_t i = 0; i < str.length(); i++)
316-
{
317-
char ch = str[i];
318-
if ((ch >= 0 && ch < 32) || ch == '/')
319-
{
320-
if (mode)
321-
{
322-
oss << "/";
323-
mode = false;
324-
}
325-
oss << "<" << std::oct << (unsigned int)ch << ">";
326-
}
327-
else
328-
{
329-
if (!mode)
330-
{
331-
oss << "/";
332-
mode = true;
333-
}
334-
oss << ch;
335-
}
336-
if (oss.tellp() >= 93 - 6)
337-
{
338-
if (mode)
339-
{
340-
oss << "/";
341-
mode = false;
342-
}
343-
AddLine(oss.str());
344-
oss.str("");
345-
oss.clear();
346-
if (i < str.length() - 1)
347-
oss << "\t.ASCII\t";
348-
}
349-
}
350-
if (oss.tellp() > 0)
351-
{
352-
if (mode)
353-
oss << "/";
354-
AddLine(oss.str());
355-
}
364+
GenerateConstString(strdeco, str);
356365
}
357366
}
358367

@@ -386,6 +395,91 @@ void Generator::GenerateVariables()
386395
}
387396
}
388397

398+
void Generator::GenerateDataBlock()
399+
{
400+
if (m_source->data.empty())
401+
return;
402+
403+
AddComment("DATA BLOCK");
404+
AddLine("\t.EVEN");
405+
406+
size_t firstdatacount = 0;
407+
ValueType firstdatatype = ValueTypeNone;
408+
size_t datacount = 0;
409+
for (size_t i = 0; i < m_source->data.size(); i++)
410+
{
411+
const DataElementModel& dataelem = m_source->data[i];
412+
string label;
413+
414+
if (datacount == 0)
415+
AddLine("D" + std::to_string(i) + ":");
416+
417+
datacount++;
418+
if (datacount >= 8000 ||
419+
i == m_source->data.size() - 1 ||
420+
(m_source->data[i + 1].vtype != dataelem.vtype || m_source->data[i + 1].fixed))
421+
{
422+
if (firstdatacount == 0)
423+
{
424+
firstdatacount = datacount; // for DATACN initialization
425+
firstdatatype = dataelem.vtype; // for DATATY
426+
}
427+
428+
// write data descriptor
429+
uint16_t descriptor = (uint16_t)((dataelem.vtype << 13) | datacount);
430+
AddLine("\t.WORD\t" + to_string_octal(descriptor) + "\t\t; " + GetValueTypeStr(dataelem.vtype) + " * " + std::to_string(datacount));
431+
432+
string line;
433+
for (size_t k = 0; k < datacount; k++)
434+
{
435+
const DataElementModel& elem = m_source->data[i + 1 - datacount + k];
436+
switch (elem.vtype)
437+
{
438+
case ValueTypeInteger:
439+
if (line.empty()) line = "\t.WORD\t"; else line += ", ";
440+
line += std::to_string((int)std::floor(elem.dvalue)) + ".";
441+
if (k % 8 == 7)
442+
{
443+
AddLine(line);
444+
line.clear();
445+
}
446+
break;
447+
case ValueTypeSingle:
448+
{
449+
if (line.empty()) line = "\t.WORD\t"; else line += ", ";
450+
uint32_t wvalue = float_to_dec_float((float)elem.dvalue);
451+
line += to_string_octal(wvalue & 0xFFFF) + "," + to_string_octal(wvalue >> 16);
452+
if (k % 4 == 3)
453+
{
454+
AddLine(line);
455+
line.clear();
456+
}
457+
break;
458+
}
459+
case ValueTypeString:
460+
GenerateConstString("", elem.svalue);
461+
break;
462+
}
463+
464+
if (!line.empty() && k == datacount - 1)
465+
{
466+
AddLine(line);
467+
line.clear();
468+
}
469+
}
470+
471+
datacount = 0;
472+
}
473+
}
474+
AddLine("\t.WORD\t0\t\t; End of DATA");
475+
476+
if (!g_turbo8)
477+
AddLine("\t.GLOBL\tDATAPT, DATATY, DATACN");
478+
AddLine("DATAPT:\t.WORD\tD0+2\t\t; Data pointer");
479+
AddLine("DATATY:\t.WORD\t" + to_string_octal(firstdatatype << 13) + "\t\t; Data type");
480+
AddLine("DATACN:\t.WORD\t" + std::to_string(firstdatacount) + ".\t\t; Data counter");
481+
}
482+
389483
void Generator::GenerateRuntimeNeeds()
390484
{
391485
AddComment("RUNTIME CALLS");
@@ -432,6 +526,10 @@ bool Generator::ProcessLine()
432526
m_line = &(m_source->lines[m_lineindex]);
433527
m_local = 0; // reset local labels counter
434528

529+
// Skip DATA lines completely, will process them in GenerateDataBlock
530+
if (m_line->statement.token.keyword == KeywordDATA)
531+
return true;
532+
435533
// Show the line text and line number, unless it's a comment line without line number
436534
if (m_line->linenum != 0 ||
437535
m_line->statement.token.keyword != KeywordREM)
@@ -448,7 +546,12 @@ bool Generator::ProcessLine()
448546

449547
void Generator::Error(const string& message)
450548
{
451-
std::cerr << "ERROR in line " << m_line->linenum << " - " << message << std::endl;
549+
std::cerr << "ERROR ";
550+
if (m_line->linenum == 0)
551+
std::cerr << "at " << m_line->srclinenum;
552+
else
553+
std::cerr << "in line " << m_line->linenum;
554+
std::cerr << " - " << message << std::endl;
452555
m_line->error = true;
453556
RegisterError();
454557
}
@@ -872,9 +975,8 @@ void Generator::GenerateColor(StatementModel& statement)
872975

873976
void Generator::GenerateData(StatementModel& statement)
874977
{
875-
//TODO
876-
AddComment("TODO DATA");
877-
m_notimplemented.insert(KeywordDATA);
978+
//NOTE: Data elements generated in DATA BLOCK
979+
assert(false); // should never fall down here
878980
}
879981

880982
void Generator::GenerateDim(StatementModel&)
@@ -1695,9 +1797,34 @@ void Generator::GeneratePrintString(const ExpressionModel& expr)
16951797

16961798
void Generator::GenerateRead(StatementModel& statement)
16971799
{
1698-
//TODO
1699-
AddComment("TODO READ");
1700-
m_notimplemented.insert(KeywordREAD);
1800+
assert(!statement.varexprs.empty());
1801+
1802+
if (m_source->data.empty())
1803+
{
1804+
Error("READ statement without any DATA to read.");
1805+
return;
1806+
}
1807+
1808+
for (const VariableExpressionModel& varexpr : statement.varexprs)
1809+
{
1810+
string deconame = varexpr.GetVariableDecoratedName();
1811+
ValueType vtype = varexpr.GetValueType();
1812+
switch (vtype)
1813+
{
1814+
case ValueTypeInteger:
1815+
AddLine("\tMOV\t#" + deconame + ", R0");
1816+
AddRuntimeCall(RuntimeREAI, "READ Integer"); // result in R0
1817+
break;
1818+
case ValueTypeSingle:
1819+
AddLine("\tMOV\t#" + deconame + ", R0");
1820+
AddRuntimeCall(RuntimeREAF, "READ Single"); // result on
1821+
break;
1822+
case ValueTypeString:
1823+
AddLine("\tMOV\t#" + deconame + ", R0");
1824+
AddRuntimeCall(RuntimeREAS, "READ String");
1825+
break;
1826+
}
1827+
}
17011828
}
17021829

17031830
void Generator::GenerateRem(StatementModel& statement)
@@ -1707,9 +1834,50 @@ void Generator::GenerateRem(StatementModel& statement)
17071834

17081835
void Generator::GenerateRestore(StatementModel& statement)
17091836
{
1710-
//TODO
1711-
AddComment("TODO RESTORE");
1712-
m_notimplemented.insert(KeywordRESTORE);
1837+
if (m_source->data.empty())
1838+
{
1839+
Error("RESTORE statement without any DATA to read.");
1840+
return;
1841+
}
1842+
1843+
int datanum = 0;
1844+
if (statement.paramline > 0)
1845+
{
1846+
// Find the source line and the DATA statement
1847+
bool linefound = false;
1848+
bool datafound = false;
1849+
int srclinenum = 0;
1850+
for (SourceLineModel& line : m_source->lines)
1851+
{
1852+
if (!linefound)
1853+
{
1854+
if (line.linenum == statement.paramline)
1855+
linefound = true;
1856+
}
1857+
if (linefound)
1858+
{
1859+
if (line.statement.token.keyword == KeywordDATA)
1860+
{
1861+
datafound = true;
1862+
srclinenum = line.srclinenum;
1863+
break;
1864+
}
1865+
}
1866+
}
1867+
assert(datafound); // should be covered in validation
1868+
assert(srclinenum > 0);
1869+
1870+
// Find that DATA element and its number
1871+
for (DataElementModel& dataelem : m_source->data)
1872+
{
1873+
if (dataelem.srclinenum == srclinenum)
1874+
break;
1875+
datanum++;
1876+
}
1877+
}
1878+
1879+
AddLine("\tMOV\t#D" + std::to_string(datanum) + ", R0");
1880+
AddRuntimeCall(RuntimeREST, "RESTORE");
17131881
}
17141882

17151883
void Generator::GenerateReturn(StatementModel& statement)

0 commit comments

Comments
 (0)