Skip to content

Commit fd8eaef

Browse files
committed
Adds support for reading DATA from a file.
Currently only supported in the cross-compiler, as the Atari compiler don't have the necessary logic to open new files from the parser. This closes #30.
1 parent 2d1ee10 commit fd8eaef

8 files changed

Lines changed: 164 additions & 4 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ COMPILER_SRC=\
280280
atarifp.cc\
281281
basic.cc\
282282
codestat.cc\
283+
ifile.cc\
283284
looptype.cc\
284285
main.cc\
285286
parser.cc\

manual.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@ General Statements
15201520
Note that the array can be modified
15211521
afterwards like a normal array.
15221522

1523+
15231524
*Advanced Usage*
15241525

15251526
Byte DATA arrays can be used to
@@ -1544,6 +1545,27 @@ General Statements
15441545
DATA ad() B. = $AD,str,$A2,0,$60
15451546
? USR(ADR(ad)), str(0)
15461547

1548+
1549+
*Loading data from a file*
1550+
1551+
The cross-compiler also supports
1552+
loading data from a file directly into
1553+
the program, using the `BYTEFILE`
1554+
(abbreviated `BYTEF.`) and `WORDFILE`
1555+
(abbreviated `WORDF.` or simply `F.`)
1556+
types and a file name enclosed in
1557+
double quotes.
1558+
1559+
Example:
1560+
1561+
DATA img() bytefile "img.raw"
1562+
DATA pos() wordfile "pos.bin"
1563+
1564+
The compiler will search the file in
1565+
the same folder than the current
1566+
basic source.
1567+
1568+
15471569
**Decrements variable by 1**
15481570
**DEC _var_ / DE.**
15491571

src/basic.syn

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ EXTERN {
9393
E_LABEL, E_LABEL_DEF
9494
E_PUSH_VAR, E_POP_VAR
9595

96+
#@if EXTENDED
97+
E_DATA_FILE
98+
#@endif
99+
96100
#@if FASTBASIC_FP
97101
E_NUMBER_FP
98102
#@endif FASTBASIC_FP
@@ -568,6 +572,10 @@ DATA_BYTES: data byte
568572
DATA_TYPE: data type
569573
TYPE_BYTE EQUAL E_LABEL_SET_TYPE DATA_BYTES
570574
TYPE_WORD EQUAL E_LABEL_SET_TYPE E_NUMBER_WORD DATA_WORDS
575+
#@if EXTENDED
576+
TYPE_BYTE "File" E_LABEL_SET_TYPE "\"" E_DATA_FILE
577+
TYPE_WORD "File" E_LABEL_SET_TYPE "\"" E_DATA_FILE
578+
#@endif
571579

572580
DATA_END:
573581
","

src/compiler/ifile.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* FastBasic - Fast basic interpreter for the Atari 8-bit computers
3+
* Copyright (C) 2017-2020 Daniel Serpell
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License along
16+
* with this program. If not, see <http://www.gnu.org/licenses/>
17+
*/
18+
19+
// ifile.cc: Opens included file
20+
21+
#include "ifile.h"
22+
#include <fstream>
23+
24+
static std::string get_path(std::string fname)
25+
{
26+
// Get's path to file. This understands either '/' or '\' as path
27+
// separators, to be compatible between Unix and Windows.
28+
auto p = fname.find_last_of("/\\");
29+
if( p != fname.npos )
30+
return fname.substr(0, p);
31+
else
32+
return std::string();
33+
}
34+
35+
36+
std::unique_ptr<std::istream> open_include_file(std::string current_file, std::string fname)
37+
{
38+
auto f = std::make_unique<std::ifstream>();
39+
40+
// Get path of current file
41+
std::string path = get_path(current_file);
42+
43+
if( !path.empty() )
44+
path = path + "/" + fname;
45+
else
46+
path = fname;
47+
48+
// Tries to open
49+
f->open(path, std::ios::binary);
50+
if( f->is_open() )
51+
return f;
52+
53+
// Try again without path
54+
f->open(fname, std::ios::binary);
55+
if( f->is_open() )
56+
return f;
57+
58+
f.reset();
59+
return f;
60+
}

src/compiler/ifile.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* FastBasic - Fast basic interpreter for the Atari 8-bit computers
3+
* Copyright (C) 2017-2019 Daniel Serpell
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License along
16+
* with this program. If not, see <http://www.gnu.org/licenses/>
17+
*/
18+
19+
// ifile.h: Opens included file
20+
21+
#pragma once
22+
23+
#include <istream>
24+
#include <memory>
25+
26+
// Opens "fname" searching first in the same path as the current file
27+
std::unique_ptr<std::istream> open_include_file(std::string current_file, std::string fname);

src/compiler/main.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ int main(int argc, char **argv)
164164
return show_error("missing output file name");
165165

166166
parse s;
167+
s.set_input_file(iname);
167168
int ln = 1;
168169
while(1)
169170
{

src/compiler/parser.cc

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
// parser.cc: C++ parser
2020

2121
#include "parser.h"
22+
#include "ifile.h"
2223
#include "vartype.h"
2324

2425
#include <algorithm>
@@ -125,15 +126,12 @@ bool SMB_E_NUMBER_BYTE(parse &s)
125126
return true;
126127
}
127128

128-
bool SMB_E_CONST_STRING(parse &s)
129+
static bool get_const_string(parse &s, std::string &str)
129130
{
130-
s.debug("E_CONST_STRING");
131-
std::string str;
132131
while( !s.eos() )
133132
{
134133
if( s.expect('"') && !s.peek('"') )
135134
{
136-
s.emit_str(str);
137135
return true;
138136
}
139137
char c = s.str[s.pos];
@@ -143,6 +141,15 @@ bool SMB_E_CONST_STRING(parse &s)
143141
return false;
144142
}
145143

144+
bool SMB_E_CONST_STRING(parse &s)
145+
{
146+
s.debug("E_CONST_STRING");
147+
std::string str;
148+
if( get_const_string(s, str) )
149+
return s.emit_str(str);
150+
return false;
151+
}
152+
146153
bool SMB_E_REM(parse &s)
147154
{
148155
s.debug("E_REM");
@@ -508,3 +515,31 @@ bool SMB_E_LABEL_SET_TYPE(parse &s)
508515
return true;
509516
}
510517

518+
// Reads a DATA array from a file
519+
bool SMB_E_DATA_FILE(parse &s)
520+
{
521+
s.debug("E_DATA_FILE");
522+
s.skipws();
523+
// Get file name until the '"'
524+
std::string fname;
525+
if( !get_const_string(s, fname) )
526+
return false;
527+
528+
auto f = open_include_file(s.in_fname, fname);
529+
if( !f )
530+
{
531+
std::cerr << s.in_fname << ":" << s.linenum << ":" << s.pos
532+
<< ": can't open data file '" << fname << "'";
533+
return false;
534+
}
535+
536+
// Read the file to a buffer of max 64k
537+
for(unsigned i=0; i<65536; i++)
538+
{
539+
int c = f->get();
540+
if( c < 0 || c > 255 )
541+
break;
542+
s.emit_byte( c );
543+
}
544+
return true;
545+
}

src/compiler/parser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class parse {
4545
std::string label;
4646
int linenum;
4747
};
48+
std::string in_fname;
4849
int sto_var;
4950
int lvl, maxlvl;
5051
std::string str;
@@ -126,6 +127,11 @@ class parse {
126127
return "EXIT without loop";
127128
}
128129

130+
void set_input_file(std::string fn)
131+
{
132+
in_fname = fn;
133+
}
134+
129135
void new_line(std::string l, int ln)
130136
{
131137
pos = max_pos = 0;

0 commit comments

Comments
 (0)