Skip to content

Commit 7bcfbde

Browse files
committed
Ready for release 0.92.0
1 parent f67af5c commit 7bcfbde

File tree

7 files changed

+95
-99
lines changed

7 files changed

+95
-99
lines changed

Mat.d

Lines changed: 47 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ class MatRead : Node {
1717
}
1818
override void codegen() {
1919
left.codegen();
20-
throw new Exception("NOT YET IMPLEMENTED");
2120
auto sz = symtab.DimSize(ident) + 1;
2221
auto idx = reg;
2322
writeln(format(" %%%d = fptosi double %%%d to i32", idx, (cast(Expr)(left)).result));
@@ -28,33 +27,12 @@ class MatRead : Node {
2827
writeln(format(" call void %%%d(i32 4, i16 %d)", fct, symtab.line)); // error: index out of bounds
2928
auto dim = reg;
3029
writeln(format(" %%%d = bitcast [ %d x double ]* %%_DATA1_%s to double*", dim, sz, symtab.getId(ident)));
31-
auto arr = reg;
32-
writeln(format(" %%%d = load double*, double** @_DATA", arr));
33-
auto gep1 = reg;
34-
writeln(format(" %%%d = getelementptr [ %d x double ], [ %d x double ]* %%%d, i32 0, i32 0",
35-
gep1, symtab.dataN, symtab.dataN, arr));
36-
auto elem = reg;
37-
writeln(format(" %%%d = load double, double* %%%d", elem, gep1));
30+
auto gep = reg;
31+
writeln(format(" %%%d = getelementptr i32, i32* %%_DATA_NUM_P, i32 0", gep));
3832
auto data = reg;
39-
writeln(format(" %%%d = bitcast double %%%d to double*", data, elem));
40-
auto gep2 = reg;
41-
writeln(format(" %%%d = getelementptr double*, double** %%_DATA_NUM_P, i32 0 ", gep2));
42-
writeln(format(" call void @mat_read(double* %%%d, i32 %%%d, double* %%%d, i32 %d, double* %%%d, i16 %u)",
43-
dim, idx, data, symtab.dataN, gep2, symtab.line));
44-
/*writeln("\tvcvt.s32.f64\ts0, d", elems.result);
45-
writeln("\tvmov\tr1, s0");
46-
writeln("\tadrl\tr0, ._size", symtab.getId(ident));
47-
writeln("\tldr\tr2, [r0]");
48-
writeln("\tcmp\tr1, r2");
49-
writeln("\tmovgt\tr0, #", 6); // error: DIM too small
50-
writeln("\tmovgt\tr1, #", symtab.line & 0xff00);
51-
writeln("\torrgt\tr1, r1, #", symtab.line & 0xff);
52-
writeln("\tblgt\truntime_error(PLT)");
53-
writeln("\tadrl\tr0, ._data", symtab.getId(ident));
54-
writeln("\tadrl\tr2, ._data_ptr");
55-
writeln("\tmov\tr3, #", symtab.line & 0xff00);
56-
writeln("\torr\tr3, r3, #", symtab.line & 0xff);
57-
writeln("\tbl\tmat_read(PLT)");*/
33+
writeln(format(" %%%d = bitcast [ %d x double ]* @_DATA to double*", data, symtab.dataN));
34+
writeln(format(" call void @mat_read(double* %%%d, i32 %%%d, double* %%%d, i32 %d, i32* %%%d, i16 %u)",
35+
dim, idx, data, symtab.dataN, gep, symtab.line));
5836
super.codegen();
5937
}
6038
}
@@ -64,30 +42,30 @@ class MatRead2 : Node {
6442
private Expr cols, rows;
6543
this(int id, Expr idx1, Expr idx2) {
6644
ident = id;
67-
rows = idx1;
68-
cols = idx2;
45+
left = new Node(idx1, idx2);
6946
symtab.initializeDim2(ident);
7047
symtab.initializeMat(ident, true);
7148
symtab.useData(true);
7249
}
7350
override void codegen() {
74-
cols.codegen();
75-
/*writeln("\tvcvt.s32.f64\ts0, d", cols.result);
76-
writeln("\tvmov\tr1, s0");
77-
writeln("\tpush\t{ r1 }");*/
78-
rows.codegen();
79-
throw new Exception("NOT YET IMPLEMENTED");
80-
/*writeln("\tvcvt.s32.f64\ts0, d", rows.result);
81-
writeln("\tvmov\tr2, s0");
82-
writeln("\tpop\t{ r1 }");
83-
writeln("\tadrl\tr0, ._mat", symtab.getId(ident));
84-
writeln("\tstr\tr2, [r0, #0]");
85-
writeln("\tstr\tr1, [r0, #4]");
86-
adrMat(0, "param1", symtab.getId(ident));
87-
writeln("\tadrl\tr1, ._data_ptr");
88-
writeln("\tmov\tr2, #", symtab.line & 0xff00);
89-
writeln("\torr\tr2, r2, #", symtab.line & 0xff);
90-
writeln("\tbl\tmat_read2(PLT)");*/
51+
left.left.codegen();
52+
auto idx1 = reg;
53+
writeln(format(" %%%d = fptosi double %%%d to i32", idx1, (cast(Expr)(left.left)).result));
54+
auto gep1 = reg;
55+
writeln(format(" %%%d = getelementptr %%struct.Dims, %%struct.Dims* %%_MAT_%s, i32 0, i32 0", gep1, symtab.getId(ident)));
56+
writeln(format(" store i32 %%%d, i32* %%%d", idx1, gep1));
57+
left.right.codegen();
58+
auto idx2 = reg;
59+
writeln(format(" %%%d = fptosi double %%%d to i32", idx2, (cast(Expr)(left.right)).result));
60+
auto gep2 = reg;
61+
writeln(format(" %%%d = getelementptr %%struct.Dims, %%struct.Dims* %%_MAT_%s, i32 0, i32 1", gep2, symtab.getId(ident)));
62+
writeln(format(" store i32 %%%d, i32* %%%d", idx2, gep2));
63+
auto gep3 = reg;
64+
writeln(format(" %%%d = getelementptr i32, i32* %%_DATA_NUM_P, i32 0", gep3));
65+
auto data = reg;
66+
writeln(format(" %%%d = bitcast [ %d x double ]* @_DATA to double*", data, symtab.dataN));
67+
writeln(format(" call void @mat_read2(%%struct.Mat* %%%d, double* %%%d, i32 %d, i32* %%%d, i16 %d)",
68+
matrix(this, ident), data, symtab.dataN, gep3, symtab.line));
9169
super.codegen();
9270
}
9371
}
@@ -332,27 +310,28 @@ class MatReadString : Node {
332310
private Expr elems;
333311
this(int id, Expr idx) {
334312
ident = id;
335-
elems = idx;
313+
left = idx;
336314
symtab.initializeDimString(ident); // note: not Dim2
337315
symtab.useData(false, true);
338316
}
339317
override void codegen() {
340-
elems.codegen();
341-
throw new Exception("NOT YET IMPLEMENTED");
342-
/*writeln("\tvcvt.s32.f64\ts0, d", elems.result);
343-
writeln("\tvmov\tr1, s0");
344-
writeln("\tadrl\tr0, ._sizeS", symtab.getId(ident));
345-
writeln("\tldr\tr2, [r0]");
346-
writeln("\tcmp\tr1, r2");
347-
writeln("\tmovgt\tr0, #", 6); // error: DIM too small
348-
writeln("\tmovgt\tr1, #", symtab.line & 0xff00);
349-
writeln("\torrgt\tr1, r1, #", symtab.line & 0xff);
350-
writeln("\tblgt\truntime_error(PLT)");
351-
writeln("\tadrl\tr0, ._dataS", symtab.getId(ident));
352-
writeln("\tadrl\tr2, ._data_ptr");
353-
writeln("\tmov\tr3, #", symtab.line & 0xff00);
354-
writeln("\torr\tr3, r3, #", symtab.line & 0xff);
355-
writeln("\tbl\tmat_read_str(PLT)");*/
318+
left.codegen();
319+
auto sz = symtab.strDimSize(ident) + 1;
320+
auto idx = reg;
321+
writeln(format(" %%%d = fptosi double %%%d to i32", idx, (cast(Expr)(left)).result));
322+
auto cmp = reg;
323+
writeln(format(" %%%d = icmp ult i32 %%%d, %d", cmp, idx, sz));
324+
auto fct = reg;
325+
writeln(format(" %%%d = select i1 %%%d, void (i32, i16)* @dummy_fct, void (i32, i16)* @runtime_error", fct, cmp));
326+
writeln(format(" call void %%%d(i32 4, i16 %d)", fct, symtab.line)); // error: index out of bounds
327+
auto dim = reg;
328+
writeln(format(" %%%d = bitcast [ %d x i8* ]* %%_DATAS_%s to i8**", dim, sz, symtab.getId(ident)));
329+
auto gep = reg;
330+
writeln(format(" %%%d = getelementptr i32, i32* %%_DATA_STR_P, i32 0", gep));
331+
auto data = reg;
332+
writeln(format(" %%%d = bitcast [ %d x i8* ]* @_DATA_STR to i8**", data, symtab.dataStrN));
333+
writeln(format(" call void @mat_read_str(i8** %%%d, i32 %%%d, i8** %%%d, i32 %d, i32* %%%d, i16 %u)",
334+
dim, idx, data, symtab.dataStrN, gep, symtab.line));
356335
super.codegen();
357336
}
358337
}
@@ -366,10 +345,11 @@ class MatPrintString : Node {
366345
symtab.initializeDimString(ident);
367346
}
368347
override void codegen() {
369-
throw new Exception("NOT YET IMPLEMENTED");
370-
/*writeln("\tadrl\tr0, ._dataS", symtab.getId(ident));
371-
writeln("\tmov\tr1, #", packed ? 1 : 0);
372-
writeln("\tbl\tmat_print_str(PLT)");*/
348+
auto dim = reg;
349+
writeln(format(" %%%d = bitcast [ %d x i8* ]* %%_DATAS_%s to i8**",
350+
dim, symtab.strDimSize(ident) + 1, symtab.getId(ident)));
351+
writeln(format(" call void @mat_print_str(i8** %%%d, i1 %s)",
352+
dim, packed ? "true" : "false"));
373353
super.codegen();
374354
}
375355
}

Node.d

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,23 @@ class Line : Node {
109109
override void codegen() {
110110
symtab.setLine(line, false);
111111
if (symtab.referencedLine(line)) {
112-
//auto bump = reg, bump2 = reg;
113112
if (status != Control.Unreachable) {
114113
writeln(" br label %.", line);
115114
}
116115
else {
117116
status = Control.Reachable;
118117
}
119-
//writeln(" unreachable\t; %", bump, " %", bump2);
120118
writeln(" .", line, ":");
121119
}
122-
else { // FIXME
123-
if (status == Control.Unreachable && right !is null) {
124-
throw new Exception("UNREACHABLE CODE");
120+
else {
121+
if (status == Control.Unreachable) {
122+
Node next = this;
123+
while (next !is null && cast(Line)next !is null && !symtab.isReferenced((cast(Line)next).line)) {
124+
next = next.right;
125+
}
126+
if (next !is null && (cast(Line)next is null || !symtab.isReferenced((cast(Line)next).line))) {
127+
throw new Exception("UNREACHABLE CODE");
128+
}
125129
}
126130
}
127131
super.codegen();
@@ -132,8 +136,6 @@ class Stop : Node {
132136
override void codegen() {
133137
writeln(" br label %exit");
134138
status = Control.Unreachable;
135-
//auto bump = reg, bump2 = reg;
136-
//writeln(" unreachable\t; %", bump, " %", bump2);
137139
super.codegen();
138140
}
139141
}
@@ -150,8 +152,6 @@ class Goto : Node {
150152
}
151153
writeln(" br label %.", line);
152154
status = Control.Unreachable;
153-
//auto bump = reg, bump2 = reg;
154-
//writeln(" unreachable\t\t; %", bump, " %", bump2);
155155
super.codegen();
156156
}
157157
}
@@ -183,8 +183,6 @@ class GoSub : Node {
183183
gep, symtab.max_depth, symtab.max_depth, ptr));
184184
writeln(format(" store i32 %d, i32* %%%d", ret, gep));
185185
writeln(" br label %.", line);
186-
//auto bump = reg;
187-
//writeln(" unreachable\t; %", bump);
188186
writeln(" return", ret, ":");
189187
super.codegen();
190188
}
@@ -196,8 +194,6 @@ class Return : Node {
196194
override void codegen() {
197195
writeln(" br label %return");
198196
status = Control.Unreachable;
199-
//auto bump = reg;
200-
//writeln(" unreachable\t; %", bump);
201197
super.codegen();
202198
}
203199
}
@@ -541,7 +537,7 @@ class InputString : Node {
541537
writeln(format(" %%%d = load i8*, i8** %%%s_", r, symtab.getId(ident)));
542538
writeln(format(" call void @free(i8* %%%d)", r));
543539
auto str = reg;
544-
writeln(format(" %%%d = call i8* @malloc(i64 %u)", str, STRING_MAX));
540+
writeln(format(" %%%d = call i8* @malloc(i32 %u)", str, STRING_MAX));
545541
writeln(format(" call void @read_string(i8* %%%d, i32 %u)", str, STRING_MAX));
546542
writeln(format(" store i8* %%%d, i8** %%%s_", str, symtab.getId(ident)));
547543
super.codegen();
@@ -621,7 +617,7 @@ class ChangeFromString : Node {
621617
auto data = reg;
622618
writeln(format(" %%%d = bitcast [ %d x double ]* %%_DATA1_%s to double*",
623619
data, symtab.DimSize(dim_id) + 1, symtab.getId(dim_id)));
624-
writeln(format(" call void @change_from_string(i8* %%%d, double* %%%d, i32 %d, i16 %d)",
620+
writeln(format(" call void @change_from_string(i8** %%%d, double* %%%d, i32 %d, i16 %d)",
625621
gep, data, symtab.DimSize(dim_id), symtab.line));
626622
super.codegen();
627623
}
@@ -641,7 +637,7 @@ class ChangeToString : Node {
641637
auto data = reg;
642638
writeln(format(" %%%d = bitcast [ %d x double ]* %%_DATA1_%s to double*",
643639
data, symtab.DimSize(dim_id) + 1, symtab.getId(dim_id)));
644-
writeln(format(" call void @change_to_string(i8* %%%d, double* %%%d, i32 %d, i16 %d)",
640+
writeln(format(" call void @change_to_string(i8** %%%d, double* %%%d, i32 %d, i16 %d)",
645641
gep, data, symtab.DimSize(dim_id), symtab.line));
646642
super.codegen();
647643
}
@@ -673,8 +669,6 @@ class OnGoto : Node {
673669
writeln(" ", label1, ":");
674670
writeln(format(" call void @runtime_error(i32 9, i16 %u)", symtab.line));
675671
writeln(" unreachable");
676-
//auto bump = reg;
677-
//writeln(" unreachable\t; %", bump);
678672
status = Control.Unreachable;
679673
super.codegen();
680674
}

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,16 @@ Wikipedia: https://en.wikipedia.org/wiki/Dartmouth_BASIC
137137

138138
## Motivation and Roadmap
139139

140-
The intention is to recreate the original programming environment that existed in the mid- to late 1960s at Dartmouth College running on a GE-225 mainframe and accessed by teletype terminals, having been inspired by the book "Endless Loop" by Mark Jones Lorenzo. The compiler is the major part of this project.
140+
The intention is to recreate the original programming environment that existed in the mid- to late- 1960s at Dartmouth College running on a GE-225 mainframe and accessed by teletype terminals, having been inspired by the book "Endless Loop" by Mark Jones Lorenzo. The compiler is the major part of this project.
141141

142142
Ultimately support for all of the early Dartmouth BASICs (First thru Sixth) is envisaged; there is a compiler switch to turn functionality on and off (`./dbasic 1` enables only First Edition keywords, for example). The complete set of keywords up to Basic The Fourth (1968) are available; the current focus is on improving the quality of the code supporting this Edition.
143143

144144
* 2023/07/11: Tag 0.90.0 (WIP) implementation of Basic The Fourth (some matrix operations not implemented in LLVM yet)
145145

146+
* 2023/07/13: Tag 0.91.1 (WIP) implementation of Basic The Fourth (added missing Target.d and updated dbasic.exe in release)
147+
148+
* 2023/07/14: Tag 0.92.1 Full implementation of Basic The Fourth (all examples work under Windows and Linux except example4-p66a.bas)
149+
146150
## Bugs
147151

148-
Please do report bugs, together with correct or incorrect BASIC input files. Note that string DATA is not supported under Linux, and there are issues with code reachability errors. I would recommend testing against the latest release or master branch, even if an earlier BASIC Edition is being used, as bugs will have been fixed while new features are being added.
152+
Please do report bugs, together with correct or incorrect BASIC input files. I recommend testing against the latest release or master branch, even if an earlier BASIC Edition is being used, as bugs will have been fixed while new features are being added.

SymbolTable.d

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ class SymbolTable {
9797
lines[l] = Line.Referenced;
9898
}
9999
}
100+
bool isReferenced(ushort l) {
101+
return l in lines && lines[l] == Line.Referenced;
102+
}
100103
int installId(string id) {
101104
auto pos = countUntil(id_list, id);
102105
if (pos != -1) {
@@ -285,6 +288,10 @@ class SymbolTable {
285288
string s = to!string(value);
286289
return (s.indexOf('.') != -1) ? s : s ~ ".0";
287290
};
291+
auto gs = (int str_id) {
292+
auto l = getStrLen(str_id) + 1;
293+
return format("([%d x i8], [%d x i8]* @_S%d, i32 0, i32 0)", l, l, str_id);
294+
};
288295
foreach (i, c; constant_list) {
289296
writeln(format("@_C%u = private constant double %s", i, g(c)));
290297
}
@@ -296,7 +303,8 @@ class SymbolTable {
296303
writeln(format("@_DATA = private constant [ %u x double ] [ %-(double %s, %) ]", dataN, gen));
297304
}
298305
if (dataStrN) {
299-
writeln(format("@_DATA_STR = private constant [ %u x i8* ] [ %-(i8* @_S%d, %) ]", dataStrN, data_str));
306+
auto gen_str = data_str.map!(gs);
307+
writeln(format("@_DATA_STR = private constant [ %u x i8* ] [ %-(i8* getelementptr inbounds %s, %) ]", dataStrN, gen_str));
300308
}
301309
writeln("\ndefine i32 @main() {");
302310
writeln(" entry:");

Target.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ declare double @acos(double noundef %0) nounwind
5454
declare double @atan(double noundef %0) nounwind
5555
declare double @log(double noundef %0) nounwind
5656
declare double @exp(double noundef %0) nounwind
57-
declare i8* @malloc(i64 noundef %0) nounwind
57+
declare i8* @malloc(i32 noundef zeroext %0) nounwind
5858
declare void @free(i8* noundef %0) nounwind
5959
declare i32 @strcmp(i8* noundef %0, i8* noundef %1) nounwind
6060
declare i32 @time(i8* noundef %0) nounwind

runtime/basic_lib.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,12 @@ void mat_print_str(char **str, bool packed) {
193193
}
194194

195195
void mat_read(double *d, unsigned sz, double *data, unsigned data_n, unsigned *data_p, short l) {
196-
printf("%p %d %p %d %p %u\n", d, sz, data, data_n, data_p, l);
197196
*d = sz;
198197
for (unsigned s = 0; s != sz; ++s) {
199198
if (*data_p == data_n) {
200199
runtime_error(1, l);
201200
}
202-
*(++d) = data[*data_p++];
201+
*++d = data[(*data_p)++];
203202
}
204203
}
205204

@@ -213,7 +212,7 @@ void mat_read2(struct Mat *m, double *data, unsigned data_n, unsigned *data_p, s
213212
if (*data_p == data_n) {
214213
runtime_error(1, l);
215214
}
216-
*(d + c + 1) = data[*data_p++];
215+
*(d + c + 1) = data[(*data_p)++];
217216
}
218217
d += m->dim->cols + 1;
219218
}
@@ -225,9 +224,9 @@ void mat_read_str(char**str, unsigned sz, char **data_str, unsigned data_str_n,
225224
runtime_error(1, l);
226225
}
227226
if (*++str) {
228-
free((void *)(*str));
227+
// free((void *)(*str));
229228
}
230-
*str = str_dup(data_str[*data_str_p++]);
229+
*str = str_dup(data_str[(*data_str_p)++]);
231230
}
232231
}
233232

@@ -454,12 +453,23 @@ void mat_input(double *d, unsigned sz, double *num, short l) {
454453
while (*p >= ' ' && s <= sz) {
455454
while ((next = strchr(p, ',')) != 0 && s < sz) {
456455
*next = '\0';
457-
sscanf(p, "%lf", ++d);
458-
++s;
456+
if (sscanf(p, "%lf", ++d) > 0) {
457+
++s;
458+
}
459+
else {
460+
--d;
461+
}
459462
p = next + 1;
460463
}
461-
p += sscanf(p, "%lf", ++d);
462-
++s;
464+
if (sscanf(p, "%lf", ++d) > 0) {
465+
++s;
466+
while (*p >= ' ' && *p != '&') {
467+
++p;
468+
}
469+
}
470+
else {
471+
--d;
472+
}
463473
if (*p == '&' && s <= sz) {
464474
print_string("? ");
465475
fgets(buffer, TmpBufSz, stdin);

runtime/run-linux.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ if [ ! -f "./runtime/basic_lib.ll" ] ; then
55
clang -S -emit-llvm -o ./runtime/basic_lib.ll ./runtime/basic_lib.c
66
fi
77

8-
./dbasic 4 < $1 > run_basic.ll && clang -O3 -o run_basic run_basic.ll ./runtime/basic_lib.ll -lm && ./run_basic
8+
./dbasic 4 < $1 > run_basic.ll && clang -O3 -Wno-override-module -o run_basic run_basic.ll ./runtime/basic_lib.ll -lm && ./run_basic

0 commit comments

Comments
 (0)