Skip to content

Commit fa677f3

Browse files
committed
BasicParser: comparison operators are left associative; multiline strings also in DATA; convert hex numbers>&7FFF to two's complement; Math.log10 for IE11; cpcBasic URL with index.html
1 parent 54b0647 commit fa677f3

32 files changed

+884
-900
lines changed

BasicLexer.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,20 @@ BasicLexer.prototype = {
191191
addToken("string", sToken, iStartPos + 1);
192192
}
193193
},
194+
fnTryContinueString = function () { // There could be a LF in a string but no CR. In CPCBasic we use LF only as EOL, so we cannot detect the difference.
195+
var sOut = "",
196+
sChar1;
197+
198+
while (isNewLine(sChar)) {
199+
sChar1 = testChar(1);
200+
if (sChar1 !== "" && (sChar1 < "0" || sChar1 > "9")) { // heuristic: next char not a digit => continue with the string
201+
sOut += advanceWhile(isNotQuotes);
202+
} else {
203+
break;
204+
}
205+
}
206+
return sOut;
207+
},
194208
fnParseCompleteLineForData = function () { // special handling because strings in data lines need not be quoted
195209
while (isNotNewLine(sChar)) {
196210
if (isWhiteSpace(sChar)) {
@@ -207,6 +221,7 @@ BasicLexer.prototype = {
207221
if (!that.bQuiet) {
208222
Utils.console.log(that.composeError({}, "Unterminated string", sToken, iStartPos + 1).message);
209223
}
224+
sToken += fnTryContinueString(); // heuristic to detect an LF in the string
210225
}
211226
sToken = sToken.replace(/\\/g, "\\\\"); // escape backslashes
212227
sToken = hexEscape(sToken);
@@ -238,20 +253,6 @@ BasicLexer.prototype = {
238253
sChar = advance();
239254
}
240255
}
241-
},
242-
fnTryContinueString = function () { // There could be a LF in a string but no CR. In CPCBasic we use LF only as EOL, so we cannot detect the difference.
243-
var sOut = "",
244-
sChar1;
245-
246-
while (isNewLine(sChar)) {
247-
sChar1 = testChar(1);
248-
if (sChar1 !== "" && (sChar1 < "0" || sChar1 > "9")) { // heuristic: next char not a digit => continue with the string
249-
sOut += advanceWhile(isNotQuotes);
250-
} else {
251-
break;
252-
}
253-
}
254-
return sOut;
255256
};
256257

257258
this.sLine = "0"; // for error messages

BasicParser.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ BasicParser.prototype = {
336336
s = oSymbols[t.type];
337337
advance(t.type);
338338
if (!s.led) {
339-
throw that.composeError(Error(), "Unexpected token", t.type, t.pos); //TTT how to get this error?
339+
throw that.composeError(Error(), "Unexpected token", t.type, t.pos); // TODO: how to get this error?
340340
}
341341
left = s.led(left); // ...the led method is invoked on the following token (infix and suffix operators), can be recursive
342342
}
@@ -520,7 +520,7 @@ BasicParser.prototype = {
520520
oRange.right = oRight || fnCreateDummyArg("null"); // insert dummy for right (do not skip it)
521521
} else if (oLeft) {
522522
oRange = oLeft; // single line number
523-
oRange.type = "linenumber"; // change type: number => linenumber //TTT
523+
oRange.type = "linenumber"; // change type: number => linenumber
524524
}
525525

526526
return oRange;
@@ -678,7 +678,7 @@ BasicParser.prototype = {
678678
var aArgs;
679679

680680
advance("(");
681-
aArgs = fnGetArgs(null); //until ")"
681+
aArgs = fnGetArgs(null); // until ")"
682682
advance(")");
683683
return aArgs;
684684
},
@@ -732,9 +732,9 @@ BasicParser.prototype = {
732732

733733
if (oToken.type === "(") { // args in parenthesis?
734734
advance("(");
735-
oValue.args = fnGetArgs(oValue.type); //until ")"
735+
oValue.args = fnGetArgs(oValue.type); // until ")"
736736
if (oToken.type !== ")") {
737-
throw that.composeError(Error(), "Expected closing parenthesis for argument list after", oPreviousToken.value, oToken.pos); //TTT
737+
throw that.composeError(Error(), "Expected closing parenthesis for argument list after", oPreviousToken.value, oToken.pos);
738738
}
739739
advance(")");
740740
} else { // no parenthesis?
@@ -930,12 +930,12 @@ BasicParser.prototype = {
930930
infix("+", 40);
931931
infix("-", 40);
932932

933-
infixr("=", 30); // equal for comparison
934-
infixr("<>", 30);
935-
infixr("<", 30);
936-
infixr("<=", 30);
937-
infixr(">", 30);
938-
infixr(">=", 30);
933+
infix("=", 30); // equal for comparison, left associative
934+
infix("<>", 30);
935+
infix("<", 30);
936+
infix("<=", 30);
937+
infix(">", 30);
938+
infix(">=", 30);
939939

940940
prefix("not", 23);
941941
infixr("and", 22);

BasicTokenizer.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,6 @@ BasicTokenizer.prototype = {
2222
// empty
2323
},
2424

25-
/*
26-
reset: function () {
27-
this.iPos = 0;
28-
this.iLine = 0;
29-
},
30-
*/
31-
3225
decode: function (sProgram) { // decode tokenized BASIC to ASCII
3326
// based on lbas2ascii.pl, 28.06.2006
3427
var that = this,

Canvas.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,13 @@ Canvas.prototype = {
103103
this.fnUpdateCanvas2Handler = this.updateCanvas2.bind(this);
104104

105105
this.iFps = 15; // FPS for canvas update
106-
//this.iTextFpsCounter = 0;
107106

108107
this.cpcAreaBox = document.getElementById("cpcAreaBox"); // TODO: move to view
109108
this.textText = document.getElementById("textText"); // TODO: move to view
110109

111110
this.aCharset = this.options.aCharset;
112111

113112
this.iGColMode = 0; // 0=normal, 1=xor, 2=and, 3=or
114-
//this.bClipped = false;
115113

116114
this.iMask = 255;
117115
this.iMaskBit = 128;

CodeGeneratorJs.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,8 @@ CodeGeneratorJs.prototype = {
4343

4444
this.iLine = 0; // current line (label)
4545

46-
/*
47-
this.oStack = {
48-
forLabel: [],
49-
forVarName: [],
50-
whileLabel: []
51-
};
52-
*/
53-
5446
this.resetCountsPerLine();
5547

56-
//this.aData = []; // collected data from data lines
5748
this.aData.length = 0;
5849

5950
this.oLabels = {}; // labels or line numbers
@@ -496,13 +487,24 @@ CodeGeneratorJs.prototype = {
496487
return node.pv;
497488
},
498489
hexnumber: function (node) {
499-
var sValue = node.value.slice(1); // remove &
490+
var sValue = node.value.slice(1), // remove &
491+
n;
500492

501493
if (sValue.charAt(0).toLowerCase() === "h") { // optional h
502494
sValue = sValue.slice(1); // remove
503495
}
504496

505-
sValue = "0x" + ((sValue.length) ? sValue : "0"); // &->0x
497+
sValue = sValue || "0";
498+
499+
n = parseInt(sValue, 16);
500+
501+
if (n > 32767) { // two's complement
502+
n = 65536 - n;
503+
sValue = "-0x" + n.toString(16);
504+
} else {
505+
sValue = "0x" + sValue;
506+
}
507+
506508
node.pt = "I";
507509
node.pv = sValue;
508510
return node.pv;
@@ -1236,7 +1238,7 @@ CodeGeneratorJs.prototype = {
12361238
},
12371239
run: function (node) { // optional arg can be number or string
12381240
if (node.args.length) {
1239-
if (node.args[0].type === "linenumber" || node.args[0].type === "number") { // optional line number //TTT should be linenumber only
1241+
if (node.args[0].type === "linenumber" || node.args[0].type === "number") { // optional line number (should be linenumber only)
12401242
this.fnAddReferenceLabel(fnParseOneArg(node.args[0]), node.args[0]); // parse only one arg, args are parsed later
12411243
}
12421244
}

CommonEventHandler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ CommonEventHandler.prototype = {
301301
sExample = this.view.getSelectValue("exampleSelect");
302302
oExample = this.model.getExample(sExample);
303303
oInFile.sCommand = "run";
304-
if (oExample && oExample.meta) { // TTT TODO: this is just a workaround, meta is in input now; should change command after loading!
304+
if (oExample && oExample.meta) { // TODO: this is just a workaround, meta is in input now; should change command after loading!
305305
sType = oExample.meta.charAt(0);
306306
if (sType === "B" || sType === "D" || sType === "G") { // binary, data only, Gena Assembler?
307307
oInFile.sCommand = "load";

Controller.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,7 @@ Controller.prototype = {
13541354
this.setInputText(sOutput, true);
13551355
this.fnPutChangedInputOnStack();
13561356

1357-
sDiff = Diff.testDiff(sInput.toUpperCase(), sOutput.toUpperCase()); //TTT: for testing
1357+
sDiff = Diff.testDiff(sInput.toUpperCase(), sOutput.toUpperCase()); // for testing
13581358
this.view.setAreaValue("outputText", sDiff);
13591359
}
13601360
if (sOutput && sOutput.length > 0) {
@@ -1593,7 +1593,7 @@ Controller.prototype = {
15931593
},
15941594

15951595
fnDirect: function () {
1596-
// TTT: break in direct mode?
1596+
// break in direct mode?
15971597
},
15981598

15991599
fnEnd: function () {
@@ -1613,7 +1613,7 @@ Controller.prototype = {
16131613
this.iNextLoopTimeOut = this.oVm.vmGetTimeUntilFrame(); // wait until next frame
16141614
},
16151615

1616-
fnOnError: function () { //TTT
1616+
fnOnError: function () {
16171617
this.oVm.vmStop("", 0, true); // continue
16181618
},
16191619

@@ -2062,7 +2062,7 @@ Controller.prototype = {
20622062
dropZone.addEventListener("dragover", this.fnHandleDragOver.bind(this), false);
20632063
dropZone.addEventListener("drop", this.fnHandleFileSelect.bind(this), false);
20642064

2065-
this.oCanvas.canvas.addEventListener("dragover", this.fnHandleDragOver.bind(this), false); //TTT fast hack
2065+
this.oCanvas.canvas.addEventListener("dragover", this.fnHandleDragOver.bind(this), false);
20662066
this.oCanvas.canvas.addEventListener("drop", this.fnHandleFileSelect.bind(this), false);
20672067

20682068
document.getElementById("fileInput").addEventListener("change", this.fnHandleFileSelect.bind(this), false);
@@ -2098,7 +2098,7 @@ Controller.prototype = {
20982098
},
20992099

21002100
// currently not used. Can be called manually: cpcBasic.controller.exportAsBase64(file);
2101-
exportAsBase64: function (sStorageName) { //TTT
2101+
exportAsBase64: function (sStorageName) {
21022102
var oStorage = Utils.localStorage,
21032103
sData = oStorage.getItem(sStorageName),
21042104
sOut = "",

CpcVm.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,7 +1688,7 @@ CpcVm.prototype = {
16881688
inp: function (iPort) {
16891689
var byte;
16901690

1691-
iPort = this.vmRound2Complement(iPort, "INP"); // 2nd complement of 16 bit address
1691+
iPort = this.vmRound2Complement(iPort, "INP"); // two's complement of 16 bit address
16921692
// eslint-disable-next-line no-bitwise
16931693
byte = (iPort & 0xff);
16941694

@@ -1765,7 +1765,7 @@ CpcVm.prototype = {
17651765
aFileData.shift(); // remove line
17661766
sLine += "\n" + aFileData[0]; // combine lines
17671767
} else {
1768-
throw that.vmComposeError(Error(), 13, "INPUT #9: no closing quotes" + value); // TTT
1768+
throw that.vmComposeError(Error(), 13, "INPUT #9: no closing quotes" + value);
17691769
}
17701770
} else { // unquoted string
17711771
iIndex = sLine.indexOf(","); // multiple args?
@@ -1809,7 +1809,7 @@ CpcVm.prototype = {
18091809
sLine = sLine.replace(/^\s+/, ""); // remove preceding whitespace
18101810
if (sType === "$") {
18111811
value = fnGetString();
1812-
} else { // number type sLine.length TTT
1812+
} else { // number type sLine.length
18131813
value = fnGetNumber();
18141814
}
18151815

@@ -2264,7 +2264,7 @@ CpcVm.prototype = {
22642264
if (sInput !== null) {
22652265
sInput = sInput.replace(/\r\n/g, "\n"); // remove CR (maybe from ASCII file in "binary" form)
22662266
if (sInput.endsWith("\n")) {
2267-
sInput = sInput.substr(0, sInput.length - 1); // remove last "\n" (TTT: also for data files?)
2267+
sInput = sInput.substr(0, sInput.length - 1); // remove last "\n" (TODO: also for data files?)
22682268
}
22692269
oInFile.aFileData = sInput.split("\n");
22702270
} else {
@@ -3346,7 +3346,7 @@ CpcVm.prototype = {
33463346
this.oCanvas.resetCustomChars();
33473347
if (iChar === 256) { // maybe move up again
33483348
iMinCharHimem = this.iMaxHimem;
3349-
this.iMaxCharHimem = iMinCharHimem; //TTT corrected
3349+
this.iMaxCharHimem = iMinCharHimem;
33503350
}
33513351
// TODO: Copy char data to screen memory, if screen starts at 0x4000 and chardata is in that range (and ram 0 is selected)
33523352
this.iMinCustomChar = iChar;
@@ -3512,9 +3512,15 @@ CpcVm.prototype = {
35123512
} else if (s.startsWith("&h")) { // hex &h
35133513
s = s.slice(2);
35143514
iNum = parseInt(s, 16);
3515+
if (iNum > 32767) { // two's complement
3516+
iNum -= 65536;
3517+
}
35153518
} else if (s.startsWith("&")) { // hex &
35163519
s = s.slice(1);
35173520
iNum = parseInt(s, 16);
3521+
if (iNum > 32767) { // two's complement
3522+
iNum -= 65536;
3523+
}
35183524
} else if (s !== "") { // not empty string?
35193525
iNum = parseFloat(s);
35203526
}

DiskImage.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ DiskImage.prototype = {
9494
oDiskInfo.sIdent = sIdent + this.readUtf(iPos + 8, 34 - 8); // read remaining ident
9595

9696
if (oDiskInfo.sIdent.substr(34 - 11, 9) !== "Disk-Info") { // some tools use "Disk-Info " instead of "Disk-Info\r\n", so compare without "\r\n"
97-
//throw this.composeError(Error(), "Disk ident not found", oDiskInfo.sIdent.substr(34 - 11, 9), iPos);
9897
// "Disk-Info" string is optional
9998
Utils.console.warn(this.composeError({}, "Disk ident not found", oDiskInfo.sIdent.substr(34 - 11, 9), iPos + 34 - 11).message);
10099
}
@@ -130,7 +129,6 @@ DiskImage.prototype = {
130129

131130
oTrackInfo.sIdent = this.readUtf(iPos, 12);
132131
if (oTrackInfo.sIdent.substr(0, 10) !== "Track-Info") { // some tools use ""Track-Info " instead of ""Track-Info\r\n", so compare without "\r\n"
133-
//throw this.composeError(Error(), "Track ident not found", oTrackInfo.sIdent.substr(0, 10), iPos);
134132
// "Track-Info" string is optional
135133
Utils.console.warn(this.composeError({}, "Track ident not found", oTrackInfo.sIdent.substr(0, 10), iPos).message);
136134
}
@@ -324,7 +322,7 @@ DiskImage.prototype = {
324322
sFormat = "data";
325323
} else if (iFirstSector === 0x41) {
326324
sFormat = "system";
327-
} else if ((iFirstSector === 0x01) && (oDiskInfo.iTracks === 80)) { // big780k TTT
325+
} else if ((iFirstSector === 0x01) && (oDiskInfo.iTracks === 80)) { // big780k
328326
sFormat = "big780k";
329327
} else {
330328
throw this.composeError(Error(), "Unknown format with sector", String(iFirstSector));

Keyboard.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ Keyboard.prototype = {
204204
this.aExpansionTokens = []; // expansion tokens 0..31 (in reality: 128..159)
205205
this.oCpcKeyExpansions = {}; // cpc keys to expansion tokens for normal, shift, ctrl; also repeat
206206

207-
//this.reset();
208207
this.bActive = false; // flag if keyboard is active/focused, set from outside
209208

210209
this.bCodeStringsRemoved = false;

0 commit comments

Comments
 (0)