@@ -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+
295351void 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\t 0\t\t ; End of DATA" );
475+
476+ if (!g_turbo8)
477+ AddLine (" \t .GLOBL\t DATAPT, DATATY, DATACN" );
478+ AddLine (" DATAPT:\t .WORD\t D0+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+
389483void 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
449547void 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
873976void 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
880982void Generator::GenerateDim (StatementModel&)
@@ -1695,9 +1797,34 @@ void Generator::GeneratePrintString(const ExpressionModel& expr)
16951797
16961798void 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 (" \t MOV\t #" + deconame + " , R0" );
1816+ AddRuntimeCall (RuntimeREAI, " READ Integer" ); // result in R0
1817+ break ;
1818+ case ValueTypeSingle:
1819+ AddLine (" \t MOV\t #" + deconame + " , R0" );
1820+ AddRuntimeCall (RuntimeREAF, " READ Single" ); // result on
1821+ break ;
1822+ case ValueTypeString:
1823+ AddLine (" \t MOV\t #" + deconame + " , R0" );
1824+ AddRuntimeCall (RuntimeREAS, " READ String" );
1825+ break ;
1826+ }
1827+ }
17011828}
17021829
17031830void Generator::GenerateRem (StatementModel& statement)
@@ -1707,9 +1834,50 @@ void Generator::GenerateRem(StatementModel& statement)
17071834
17081835void 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 (" \t MOV\t #D" + std::to_string (datanum) + " , R0" );
1880+ AddRuntimeCall (RuntimeREST, " RESTORE" );
17131881}
17141882
17151883void Generator::GenerateReturn (StatementModel& statement)
0 commit comments