diff --git a/README.md b/README.md index 319f2a2..573d44e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Line numbers are optional and only needed to start a subroutine or a *DATA* line LocoBasic Links: [LocoBasic](https://benchmarko.github.io/LocoBasic/), [Source code](https://github.com/benchmarko/LocoBasic/), -[HTML Readme](https://github.com/benchmarko/LocoBasic/#readme), +[HTML Readme](https://github.com/benchmarko/LocoBasic/#readme) ## Getting Started @@ -97,6 +97,8 @@ LocoBasic Links: - Separated by commas "," - Strings must be quoted - Numbers (including hex and binary) are unquoted and can only be read numerically + - `DEC$(number, format)` Returns the number as a string formatted according to the specified pattern. + - Only "#" and "." are supported in the format. Example: "##.###" - `DEF FNname[(arg1, ...)] = expression` Defines a function *FNname* - Can be used as `FNname()` - No space between *FN* and *name* is allowed @@ -142,7 +144,7 @@ LocoBasic Links: - `PRINT argument1 [; argument2; ...]` Outputs text and numbers - Arguments must be separated by `;` - Numbers are padded with trailinng space, and leading space for positive numbers - - **Limitations:** No support for `TAB()`, `SPC()`, or `USING` formatting + - **Limitations:** No support for `TAB()`, `SPC()`, or `USING` formatting. Use *DEC$()* to format numbers - `READ variable` Reads the next value from a `DATA` statement into *variable* - `REM` A comment until end of line, same as ` - `RESTORE [line]` Resets the `DATA` pointer to a specified *line* number @@ -223,7 +225,7 @@ after auto border break call cat chain clear cog closein closeout cont copychr ### Resources -- [Ohm](https://ohmjs.org/) JavaScript parsing toolkit - [Source code](https://github.com/ohmjs/ohm) +- [Ohm](https://ohmjs.org/) JavaScript parsing toolkit - [Source code](https://github.com/ohmjs/ohm) - Paper: [Modular Semantic Actions](https://ohmjs.org/pubs/dls2016/modular-semantic-actions.pdf) - [CodeMirror](https://codemirror.net/) code editor used for the Locobasic UI - [Source code](https://github.com/codemirror/dev/) - diff --git a/dist/examples/examples.js b/dist/examples/examples.js index 3f2797c..72c595d 100644 --- a/dist/examples/examples.js +++ b/dist/examples/examples.js @@ -327,7 +327,7 @@ REM printResult(): void 3500 PRINT: PRINT "Throughput for all benchmarks (loops per sec):" PRINT "BMR ("; prgLanguage$; ") :"; FOR bench = bench1 TO bench2 -PRINT round(benchres(bench),3); 'PRINT USING "#######.### "; benchres(bench); +PRINT dec$(benchres(bench), "#######.###");" "; 'PRINT USING "#######.### "; benchres(bench); NEXT bench PRINT RETURN @@ -360,10 +360,10 @@ if tDelta < 0 THEN tDelta = -tDelta REM xx IF tEsti > tMeas THEN tDelta = tEsti - tMeas ELSE tDelta = tMeas - tEsti loopsPsec = 0 IF tMeas > 0 THEN loopsPsec = (loops * 1000) / tMeas -PRINT round(loopsPsec, 3); 'USING "######.###";loopsPsec; -PRINT "/s (time="; round(tMeas, 3); 'USING "#####.###"; tMeas; -PRINT " ms, loops="; loops; 'USING "#######"; loops; -PRINT ", delta="; round(tDelta, 3);: PRINT " ms)" 'USING "#####.###"; tDelta;: PRINT " ms)" +PRINT dec$(loopsPsec, "######.###"); 'USING "######.###";loopsPsec; +PRINT "/s (time="; dec$(tMeas, "#####.###"); 'USING "#####.###"; tMeas; +PRINT " ms, loops="; dec$(loops, "#######"); 'USING "#######"; loops; +PRINT ", delta="; dec$(tDelta, "#####.###");: PRINT " ms)" 'USING "#####.###"; tDelta;: PRINT " ms)" IF x <> -1 then gosub 4200 else throughput = -1 WEND RETURN @@ -850,93 +850,95 @@ PRINT "":PRINT "=> max:";STR$(mx);", CPC";mhz;"MHz" cpcBasic.addItem("", ` 100 REM crypto1 - Cryptology 1 (Kryptoanalyse - Kryptologie) -110 '"Die geheime Nachricht/Umschau Verlag/S.63" +110 'Die geheime Nachricht, Umschau Verlag, S.63 120 '16.11.1988 130 ' -160 DIM z(5,27):'6 Sprachen mit 28 Daten : 26 Buchstaben+ Vokale/Konson. -170 'Einlesen der Buchstabenhaeufigkeit: +160 DIM z(5,27): '6 languages with 28 data points: 26 letters + vowels/consonants +170 'Reading the frequency of letters 180 FOR j=0 TO 5:FOR i=0 TO 27:READ z(j,i):NEXT i,j 190 MODE 2 -200 PRINT "Kryptoanalyse - Kryptologie" -210 PRINT"Anteil der Buchstaben in % :" -230 PRINT"Deutsch:";" Englisch:";" Franzoesisch";" Italienisch:";" Spanisch:";" Portug." -240 FOR i=0 TO 27:FOR j=0 TO 5 -250 IF j=0 THEN PRINT CHR$(i+65)+" "; -260 PRINT z(j,i);:NEXT j -262 ? -265 'if i=22 then t=time+900:while time0 cls PRINT"L I F E G A M E" - gosub 1000 + gosub 300 t=time+50:while time 3) THEN nextGrid(x, y) = 0 + IF grid(x, y) = 0 AND neighbors = 3 THEN nextGrid(x, y) = 1 + IF grid(x, y) = 1 AND neighbors = 2 OR neighbors = 3 THEN nextGrid(x, y) = 1 + NEXT y + print + NEXT x + 'SWAP grid, nextGrid +FOR x = 1 TO rows + FOR y = 1 TO cols + grid(x, y) = nextGrid(x, y) + NEXT y +NEXT x + 'SLEEP 100 + t=time+40:while time0 THEN PRINT STRING$(4,CHR$(65+p)); ELSE PRINT STRING$(4," "); + IF p>0 THEN ch$=CHR$(65+p) ELSE ch$=" " + PRINT STRING$(4,ch$); NEXT x ? NEXT y @@ -1611,7 +1650,7 @@ FOR loop = 1 TO loops NEXT t=TIME-t PRINT "Number of primes below ";n;": ";x -PRINT "Loops:";loops;"; Time:";t +PRINT "Loops:";loops;"; Time:";round(t*10/3, 3);"ms;" STOP ' 1000 'compute @@ -1653,7 +1692,11 @@ cpcBasic.addItem("", ` cpcBasic.addItem("", ` REM testsub - Test Subroutines +cls ?"start" +gosub 350 +?"end" +stop ' 100 ?"sub100" RETURN @@ -1671,10 +1714,13 @@ GOSUB 200 'gosub 400 RETURN ' +350 'main +gosub 100 +gosub 200 GOSUB 300 a=1 ON a GOSUB 200, 300 -?"at end" +return `); cpcBasic.addItem("", ` @@ -1934,7 +1980,15 @@ DATA &a7, &x10100111 READ a:IF a<>&A7 THEN ERROR 33 READ a:IF a<>&A7 THEN ERROR 33 ' -''a$=dec$(3,"##.##") +PRINT "DEC$, "; +a$=DEC$(0,"##.##"): IF a$<>" 0.00" THEN ERROR 33 +a$=DEC$(-1.2,"##.##"): IF a$<>"-1.20" THEN ERROR 33 +''a$=DEC$(1.005,"##.##"): IF a$<>" 1.01" THEN ERROR 33 +a$=DEC$(3,"###.##"): IF a$<>" 3.00" THEN ERROR 33 +a$=DEC$(2.9949,"#.##"): IF a$<>"2.99" THEN ERROR 33 +''a$=DEC$(8.575,"##.##"): IF a$<>" 8.58" THEN ERROR 33 +a$=DEC$(8.595,"##.##"): IF a$<>" 8.60" THEN ERROR 33 +''a$=DEC$(15.355,"#.##"): IF a$<>"15.36" THEN ERROR 33 ' PRINT "DEF FN (and FN), "; def fnclk=10 diff --git a/package.json b/package.json index 06178db..5261bcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "locobasic", - "version": "0.1.21", + "version": "0.1.22", "description": "# LocoBasic - Loco BASIC", "type": "commonjs", "scripts": { diff --git a/src/Semantics.ts b/src/Semantics.ts index 350a75b..b4e58f0 100644 --- a/src/Semantics.ts +++ b/src/Semantics.ts @@ -61,6 +61,14 @@ function getCodeSnippets() { cls: function cls() { _o.cls(); }, + dec$: function dec$(num: number, format: string) { + const [, decimalPart] = format.split(".", 2); + const decimals = decimalPart ? decimalPart.length : 0; + const str = num.toFixed(decimals); + const padLen = format.length - str.length; + const pad = padLen > 0 ? " ".repeat(padLen) : ""; + return pad + str; + }, dim: function dim(dims: number[], initVal: string | number = 0) { const createRecursiveArray = (depth: number): RecursiveArray => { const length = dims[depth] + 1; // +1 because of 0-based index @@ -343,6 +351,11 @@ function getSemantics(semanticsHelper: SemanticsHelper) { return ""; }, + DecS(_decLit: Node, _open: Node, num: Node, _comma: Node, format: Node, _close: Node) { // eslint-disable-line @typescript-eslint/no-unused-vars + semanticsHelper.addInstr("dec$"); + return `dec$(${num.eval()}, ${format.eval()})`; + }, + Def(_defLit: Node, _fnLit: Node, assign: Node) { return `${assign.eval()}`; }, diff --git a/src/arithmetic.ts b/src/arithmetic.ts index 6a40082..9990e80 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -85,6 +85,9 @@ export const arithmetic = { Data = data NonemptyListOf + DecS + = decS "(" NumExp "," StrExp ")" + Def = def fn DefAssign @@ -252,6 +255,7 @@ export const arithmetic = { = "(" StrExp ")" -- paren | BinS | ChrS + | DecS | HexS | LeftS | LowerS