gwbasickernel 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gwbasickernel-0.1.0/LICENSE +21 -0
- gwbasickernel-0.1.0/MANIFEST.in +2 -0
- gwbasickernel-0.1.0/PKG-INFO +101 -0
- gwbasickernel-0.1.0/README.md +247 -0
- gwbasickernel-0.1.0/gwbasickernel/README.md +80 -0
- gwbasickernel-0.1.0/gwbasickernel/__init__.py +3 -0
- gwbasickernel-0.1.0/gwbasickernel/__main__.py +4 -0
- gwbasickernel-0.1.0/gwbasickernel/basic_lexer.py +79 -0
- gwbasickernel-0.1.0/gwbasickernel/install.py +60 -0
- gwbasickernel-0.1.0/gwbasickernel/kernel.json +8 -0
- gwbasickernel-0.1.0/gwbasickernel/kernel.py +575 -0
- gwbasickernel-0.1.0/gwbasickernel/test_kernel.py +140 -0
- gwbasickernel-0.1.0/gwbasickernel.egg-info/PKG-INFO +101 -0
- gwbasickernel-0.1.0/gwbasickernel.egg-info/SOURCES.txt +19 -0
- gwbasickernel-0.1.0/gwbasickernel.egg-info/dependency_links.txt +1 -0
- gwbasickernel-0.1.0/gwbasickernel.egg-info/entry_points.txt +5 -0
- gwbasickernel-0.1.0/gwbasickernel.egg-info/requires.txt +3 -0
- gwbasickernel-0.1.0/gwbasickernel.egg-info/top_level.txt +1 -0
- gwbasickernel-0.1.0/pyproject.toml +40 -0
- gwbasickernel-0.1.0/setup.cfg +4 -0
- gwbasickernel-0.1.0/tests/test_kernel_package.py +84 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eremey Valetov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gwbasickernel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Jupyter kernel for GW-BASIC 2026 with inline graphics
|
|
5
|
+
Author: Eremey Valetov
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/evvaletov/gw-basic-2026
|
|
8
|
+
Project-URL: Documentation, https://evvaletov.github.io/gw-basic-2026/
|
|
9
|
+
Project-URL: Issues, https://github.com/evvaletov/gw-basic-2026/issues
|
|
10
|
+
Classifier: Framework :: Jupyter
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Operating System :: MacOS
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: ipykernel>=6
|
|
18
|
+
Requires-Dist: jupyter_client>=8
|
|
19
|
+
Requires-Dist: pygments>=2
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# GW-BASIC Jupyter kernel
|
|
23
|
+
|
|
24
|
+
Run GW-BASIC programs in JupyterLab or Notebook. Variables and program lines
|
|
25
|
+
persist between cells. The kernel converts the interpreter's Sixel output to
|
|
26
|
+
inline PNG images, so the notebook browser does not need Sixel support.
|
|
27
|
+
|
|
28
|
+
Requires Python 3.10 or later and the native
|
|
29
|
+
[GW-BASIC 2026 interpreter](https://github.com/evvaletov/gw-basic-2026)
|
|
30
|
+
on Linux or macOS. The Python package does not include that interpreter.
|
|
31
|
+
The DOS executables cannot be used as the notebook backend.
|
|
32
|
+
|
|
33
|
+
## Install the interpreter
|
|
34
|
+
|
|
35
|
+
With Homebrew on Linux or macOS:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
brew tap evvaletov/gwbasic https://github.com/evvaletov/gw-basic-2026.git
|
|
39
|
+
brew install evvaletov/gwbasic/gwbasic
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The Homebrew formula builds from a pinned source revision. It includes the
|
|
43
|
+
interpreter and native compiler, with PulseAudio disabled.
|
|
44
|
+
|
|
45
|
+
Alternatively, build from source with a C11 compiler and CMake:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
git clone https://github.com/evvaletov/gw-basic-2026.git
|
|
49
|
+
cd gw-basic-2026
|
|
50
|
+
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
|
51
|
+
cmake --build build --parallel 2
|
|
52
|
+
export GWBASIC="$PWD/build/gwbasic"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Install the kernel
|
|
56
|
+
|
|
57
|
+
Create a Python environment for the kernel and JupyterLab:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
python3 -m venv .venv
|
|
61
|
+
. .venv/bin/activate
|
|
62
|
+
python -m pip install gwbasickernel jupyterlab
|
|
63
|
+
gwbasickernel-install --sys-prefix
|
|
64
|
+
jupyter lab
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Choose **GW-BASIC 2026** when creating a notebook. The kernel looks for the
|
|
68
|
+
interpreter in `GWBASIC`, then on `PATH`. To save its location in the kernelspec,
|
|
69
|
+
use this command instead of the installer command above:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
gwbasickernel-install --sys-prefix --gwbasic /absolute/path/to/gwbasic
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If Jupyter runs in another Python environment, use `--user` to register the
|
|
76
|
+
kernel for your account. Keep the kernel's Python environment in place:
|
|
77
|
+
the kernelspec records its Python executable.
|
|
78
|
+
|
|
79
|
+
## Try it
|
|
80
|
+
|
|
81
|
+
```basic
|
|
82
|
+
10 FOR N=1 TO 8
|
|
83
|
+
20 PRINT N;N*N
|
|
84
|
+
30 NEXT N
|
|
85
|
+
RUN
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For graphics, clear the previous program first:
|
|
89
|
+
|
|
90
|
+
```basic
|
|
91
|
+
NEW
|
|
92
|
+
10 SCREEN 1
|
|
93
|
+
20 CIRCLE (160,100),80,2
|
|
94
|
+
RUN
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
See the [executed graphics notebook](https://github.com/evvaletov/gw-basic-2026/blob/main/examples/graphics.ipynb)
|
|
98
|
+
and [demo guide](https://github.com/evvaletov/gw-basic-2026/blob/main/docs/demos.md).
|
|
99
|
+
|
|
100
|
+
`%new` clears the BASIC program; `%reset` starts a fresh interpreter process.
|
|
101
|
+
`%timeout 60` changes the output wait timeout from its default of 30 seconds.
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# GW-BASIC 2026
|
|
2
|
+
|
|
3
|
+
A portable C reimplementation of Microsoft GW-BASIC, using the
|
|
4
|
+
[original 8088 assembly source](https://github.com/microsoft/GW-BASIC)
|
|
5
|
+
(released by Microsoft in 2020) as the authoritative reference.
|
|
6
|
+
|
|
7
|
+
The interpreter implements the language in C11 and aims to reproduce the
|
|
8
|
+
original behavior. Hardware access uses emulation or device stubs; see the
|
|
9
|
+
[language reference](docs/language-reference.md) for their limits.
|
|
10
|
+
|
|
11
|
+
## Demos
|
|
12
|
+
|
|
13
|
+
### FreeDOS editor
|
|
14
|
+
|
|
15
|
+
The 16-bit interpreter, installed with FreeDOS's FDINST package installer, listing and running [squares.bas](examples/squares.bas) in QEMU:
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
### Native compilation
|
|
20
|
+
|
|
21
|
+
The same listing compiles through C to a native executable. These commands run from the repository root after building:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
cp examples/squares.bas build/squares.bas
|
|
25
|
+
build/gwbasic-compile build/squares.bas -c --keep-c --runtime .
|
|
26
|
+
build/squares
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The executable prints the same table of squares as the interpreter. `build/squares.c` contains the generated C.
|
|
30
|
+
|
|
31
|
+
### Notebook graphics
|
|
32
|
+
|
|
33
|
+
[graphics.ipynb](examples/graphics.ipynb) runs [circles.bas](examples/circles.bas) through the Jupyter kernel. The kernel converts the interpreter's Sixel output to inline PNG images. This preview shows the final frame from the executed notebook's HTML export:
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
See [Reproducing the demos](docs/demos.md) for installation, commands, capture details and limitations.
|
|
38
|
+
|
|
39
|
+
## Building
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
mkdir -p build
|
|
43
|
+
(cd build && cmake ..)
|
|
44
|
+
cmake --build build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The POSIX build requires a C11 compiler, CMake 3.12+, and `pkg-config`.
|
|
48
|
+
PulseAudio (`libpulse-simple`) is optional and detected at build time for
|
|
49
|
+
`SOUND`/`BEEP`/`PLAY` audio output.
|
|
50
|
+
|
|
51
|
+
Builds three targets:
|
|
52
|
+
|
|
53
|
+
- `gwbasic` -- the interpreter
|
|
54
|
+
- `gwbasic-compile` -- the ahead-of-time compiler
|
|
55
|
+
- `libgwrt.a` -- runtime library for compiled programs
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
Run these commands from the repository root. Interactive mode launches a
|
|
60
|
+
GW-BASIC-style full-screen editor:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
$ build/gwbasic
|
|
64
|
+
GW-BASIC 2026 0.18.2
|
|
65
|
+
(C) Eremey Valetov 2026. MIT License.
|
|
66
|
+
Based on Microsoft GW-BASIC assembly source.
|
|
67
|
+
Ok
|
|
68
|
+
PRINT 2+2
|
|
69
|
+
4
|
|
70
|
+
Ok
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Run a program file (ASCII or binary tokenized):
|
|
74
|
+
|
|
75
|
+
<!-- docs-test: readme-run -->
|
|
76
|
+
```bash
|
|
77
|
+
build/gwbasic tests/programs/prime_sieve.bas
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Compile to a native executable:
|
|
81
|
+
|
|
82
|
+
<!-- docs-test: readme-compile -->
|
|
83
|
+
```bash
|
|
84
|
+
build/gwbasic-compile tests/programs/fibonacci.bas -c --runtime .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Ahead-of-Time Compiler
|
|
88
|
+
|
|
89
|
+
`gwbasic-compile` translates ASCII BASIC programs to C source. With `-c`,
|
|
90
|
+
it invokes GCC to produce native executables linked against `libgwrt.a`.
|
|
91
|
+
GCC is required for this path even if the interpreter was built with Clang.
|
|
92
|
+
|
|
93
|
+
Pipeline: `.bas` → tokenizer → analysis → C codegen → `gcc` → native binary.
|
|
94
|
+
|
|
95
|
+
The compiler test harness compares eligible programs with the expected-output
|
|
96
|
+
files. It skips interactive, timing-dependent, and audio tests, plus helper
|
|
97
|
+
programs loaded by other tests. Passing that suite does not establish full
|
|
98
|
+
GW-BASIC compatibility; compiled timer and key event handlers are unsupported.
|
|
99
|
+
|
|
100
|
+
Save this example as `myprog.bas`:
|
|
101
|
+
|
|
102
|
+
<!-- docs-test: readme-program -->
|
|
103
|
+
```basic
|
|
104
|
+
10 PRINT "HELLO FROM BASIC"
|
|
105
|
+
20 END
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
<!-- docs-test: readme-compiler -->
|
|
109
|
+
```bash
|
|
110
|
+
# Generate C source
|
|
111
|
+
build/gwbasic-compile myprog.bas -o myprog.c
|
|
112
|
+
|
|
113
|
+
# Compile to executable (automatic)
|
|
114
|
+
build/gwbasic-compile myprog.bas -c --runtime .
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## VS Code extension
|
|
118
|
+
|
|
119
|
+
The [VS Code extension](editors/vscode/README.md) adds highlighting, snippets,
|
|
120
|
+
F5 Run, and native compilation in the integrated terminal. Install its VSIX
|
|
121
|
+
from the `vscode-extension-stable` CI artifact, then configure the interpreter and
|
|
122
|
+
compiler paths. The extension and runtime are packaged separately.
|
|
123
|
+
|
|
124
|
+
## Homebrew
|
|
125
|
+
|
|
126
|
+
Install the interpreter and native compiler on Linux or macOS:
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
brew tap evvaletov/gwbasic https://github.com/evvaletov/gw-basic-2026.git
|
|
130
|
+
brew install evvaletov/gwbasic/gwbasic
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The formula builds from a pinned source revision with PulseAudio disabled.
|
|
134
|
+
`gwbasic-compile program.bas -c` uses the installed runtime automatically.
|
|
135
|
+
Native compilation requires `gcc` on `PATH` (Apple's `gcc` command invokes
|
|
136
|
+
Clang on macOS).
|
|
137
|
+
|
|
138
|
+
## Jupyter Kernel
|
|
139
|
+
|
|
140
|
+
A Jupyter notebook kernel for GW-BASIC with inline Sixel graphics
|
|
141
|
+
rendering, INPUT support, and Pygments syntax highlighting. Requires Python
|
|
142
|
+
3.10 or later and the native interpreter on Linux or macOS.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
python3 -m venv .venv
|
|
146
|
+
. .venv/bin/activate
|
|
147
|
+
python -m pip install gwbasickernel jupyterlab
|
|
148
|
+
gwbasickernel-install --sys-prefix
|
|
149
|
+
jupyter lab # select "GW-BASIC 2026" kernel
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
See the [kernel installation guide](gwbasickernel/README.md) for interpreter
|
|
153
|
+
setup and kernels installed in a different Python environment. To develop the
|
|
154
|
+
kernel from this checkout, use `python -m pip install -e .`.
|
|
155
|
+
|
|
156
|
+
## What Works
|
|
157
|
+
|
|
158
|
+
The interpreter covers the language features below. Device-specific operations
|
|
159
|
+
include emulated ports, fixed return values, and unsupported machine-code calls.
|
|
160
|
+
|
|
161
|
+
Data types: INTEGER (%), SINGLE (!), DOUBLE (#), STRING ($)
|
|
162
|
+
|
|
163
|
+
Operators: `+ - * / ^ \ MOD AND OR XOR EQV IMP NOT < = > <= >= <>`
|
|
164
|
+
|
|
165
|
+
Statements:
|
|
166
|
+
|
|
167
|
+
| Category | Statements |
|
|
168
|
+
|----------|------------|
|
|
169
|
+
| Output | PRINT, LPRINT, LLIST, PRINT USING, WRITE, CLS |
|
|
170
|
+
| Variables | LET, DIM, ERASE, SWAP, DEFINT/SNG/DBL/STR |
|
|
171
|
+
| Control flow | GOTO, GOSUB/RETURN, FOR/NEXT, IF/THEN/ELSE, WHILE/WEND, ON...GOTO/GOSUB |
|
|
172
|
+
| Input | INPUT, LINE INPUT, DATA/READ/RESTORE, INKEY$ |
|
|
173
|
+
| Program | RUN, CONT, STOP, END, NEW, LIST, CLEAR, AUTO, RENUM, DELETE, EDIT |
|
|
174
|
+
| Sequential I/O | OPEN, CLOSE, PRINT#, WRITE#, INPUT#, LINE INPUT# |
|
|
175
|
+
| Random-access I/O | FIELD, LSET, RSET, PUT, GET, CVI/CVS/CVD, MKI$/MKS$/MKD$ |
|
|
176
|
+
| Program I/O | SAVE (binary/ASCII), LOAD (auto-detects), MERGE, CHAIN, COMMON |
|
|
177
|
+
| Event trapping | ON TIMER(n) GOSUB, TIMER ON/OFF/STOP, ON KEY(n) GOSUB |
|
|
178
|
+
| Error handling | ON ERROR GOTO, RESUME, ERROR, ERR, ERL |
|
|
179
|
+
| User functions | DEF FN, RANDOMIZE |
|
|
180
|
+
| File management | KILL, NAME, FILES, MKDIR, RMDIR, CHDIR, SHELL, ENVIRON |
|
|
181
|
+
| Date/time | DATE$, TIME$, TIMER |
|
|
182
|
+
| Screen | LOCATE, COLOR, WIDTH, SCREEN, KEY ON/OFF/LIST |
|
|
183
|
+
| Graphics | PSET, PRESET, LINE, CIRCLE, DRAW, PAINT, GET/PUT (sprites), VIEW, WINDOW, PALETTE, PMAP |
|
|
184
|
+
| Sound | SOUND, BEEP, PLAY (MML) |
|
|
185
|
+
| Memory | DEF SEG, PEEK, POKE, BSAVE, BLOAD |
|
|
186
|
+
| Hardware I/O | OUT, INP, WAIT, MOTOR, STICK, STRIG |
|
|
187
|
+
|
|
188
|
+
## Tests
|
|
189
|
+
|
|
190
|
+
Run the regression suites from the repository root:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
python3 tests/test_harnesses.py # harness failure and timeout checks
|
|
194
|
+
bash tests/run_tests.sh # interpreter
|
|
195
|
+
bash tests/run_compiler_tests.sh # compiled programs
|
|
196
|
+
bash tests/run_corpus.sh --report corpus-matrix.json # curated compatibility cases
|
|
197
|
+
python3 -m gwbasickernel.test_kernel # Jupyter kernel
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
For an interpreter run without audio playback:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
PULSE_SERVER=unix:/tmp/gwbasic-no-audio-server bash tests/run_tests.sh
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
This points PulseAudio at an unavailable socket, as the interpreter CI step does.
|
|
207
|
+
Audio fixtures have a 30-second limit so they can also finish with a live server.
|
|
208
|
+
Output mismatches, execution failures, and timeouts fail the suites. See
|
|
209
|
+
[Development](docs/development.md) for timeout settings and test coverage.
|
|
210
|
+
|
|
211
|
+
The [compatibility corpus](tests/corpus/README.md) contains 98 original BASIC
|
|
212
|
+
Computer Games listings. Its automated runtime suite checks 53 fixed-input cases
|
|
213
|
+
from twenty-six listings against Microsoft GW-BASIC transcripts and compares six
|
|
214
|
+
compiler modes with the interpreter. The other listings have build-audit
|
|
215
|
+
coverage only. Awari and Checkers compile; Super Star Trek is rejected for an
|
|
216
|
+
unspaced `TO` expression that Microsoft GW-BASIC also rejects.
|
|
217
|
+
|
|
218
|
+
## DOS / FreeDOS
|
|
219
|
+
|
|
220
|
+
Cross-compiles to DOS with OpenWatcom V2:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
wmake -f Makefile.dos16 # 16-bit real mode, no extender
|
|
224
|
+
wmake -f Makefile.dos # 32-bit DOS/4GW, requires DOS4GW.EXE
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The 16-bit build runs on FreeDOS, MS-DOS, and compatible systems without
|
|
228
|
+
a DOS extender. See [Getting Started](docs/getting-started.md) for details.
|
|
229
|
+
|
|
230
|
+
## Release archives
|
|
231
|
+
|
|
232
|
+
The v0.18.2 [release notes](RELEASE_NOTES.md) describe the Linux and DOS archives,
|
|
233
|
+
checksums, and validation limits. CI builds archives after its checks pass;
|
|
234
|
+
publication is a separate step.
|
|
235
|
+
|
|
236
|
+
## Documentation
|
|
237
|
+
|
|
238
|
+
Full Sphinx documentation in `docs/`:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
cd docs && pip install -r requirements.txt && make html
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
The implementation uses the [MIT License](LICENSE). The vendored BASIC Computer
|
|
247
|
+
Games listings in `tests/corpus/` use the upstream [Unlicense](tests/corpus/LICENSE).
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# GW-BASIC Jupyter kernel
|
|
2
|
+
|
|
3
|
+
Run GW-BASIC programs in JupyterLab or Notebook. Variables and program lines
|
|
4
|
+
persist between cells. The kernel converts the interpreter's Sixel output to
|
|
5
|
+
inline PNG images, so the notebook browser does not need Sixel support.
|
|
6
|
+
|
|
7
|
+
Requires Python 3.10 or later and the native
|
|
8
|
+
[GW-BASIC 2026 interpreter](https://github.com/evvaletov/gw-basic-2026)
|
|
9
|
+
on Linux or macOS. The Python package does not include that interpreter.
|
|
10
|
+
The DOS executables cannot be used as the notebook backend.
|
|
11
|
+
|
|
12
|
+
## Install the interpreter
|
|
13
|
+
|
|
14
|
+
With Homebrew on Linux or macOS:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
brew tap evvaletov/gwbasic https://github.com/evvaletov/gw-basic-2026.git
|
|
18
|
+
brew install evvaletov/gwbasic/gwbasic
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The Homebrew formula builds from a pinned source revision. It includes the
|
|
22
|
+
interpreter and native compiler, with PulseAudio disabled.
|
|
23
|
+
|
|
24
|
+
Alternatively, build from source with a C11 compiler and CMake:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
git clone https://github.com/evvaletov/gw-basic-2026.git
|
|
28
|
+
cd gw-basic-2026
|
|
29
|
+
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
|
30
|
+
cmake --build build --parallel 2
|
|
31
|
+
export GWBASIC="$PWD/build/gwbasic"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Install the kernel
|
|
35
|
+
|
|
36
|
+
Create a Python environment for the kernel and JupyterLab:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
python3 -m venv .venv
|
|
40
|
+
. .venv/bin/activate
|
|
41
|
+
python -m pip install gwbasickernel jupyterlab
|
|
42
|
+
gwbasickernel-install --sys-prefix
|
|
43
|
+
jupyter lab
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Choose **GW-BASIC 2026** when creating a notebook. The kernel looks for the
|
|
47
|
+
interpreter in `GWBASIC`, then on `PATH`. To save its location in the kernelspec,
|
|
48
|
+
use this command instead of the installer command above:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
gwbasickernel-install --sys-prefix --gwbasic /absolute/path/to/gwbasic
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If Jupyter runs in another Python environment, use `--user` to register the
|
|
55
|
+
kernel for your account. Keep the kernel's Python environment in place:
|
|
56
|
+
the kernelspec records its Python executable.
|
|
57
|
+
|
|
58
|
+
## Try it
|
|
59
|
+
|
|
60
|
+
```basic
|
|
61
|
+
10 FOR N=1 TO 8
|
|
62
|
+
20 PRINT N;N*N
|
|
63
|
+
30 NEXT N
|
|
64
|
+
RUN
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
For graphics, clear the previous program first:
|
|
68
|
+
|
|
69
|
+
```basic
|
|
70
|
+
NEW
|
|
71
|
+
10 SCREEN 1
|
|
72
|
+
20 CIRCLE (160,100),80,2
|
|
73
|
+
RUN
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
See the [executed graphics notebook](https://github.com/evvaletov/gw-basic-2026/blob/main/examples/graphics.ipynb)
|
|
77
|
+
and [demo guide](https://github.com/evvaletov/gw-basic-2026/blob/main/docs/demos.md).
|
|
78
|
+
|
|
79
|
+
`%new` clears the BASIC program; `%reset` starts a fresh interpreter process.
|
|
80
|
+
`%timeout 60` changes the output wait timeout from its default of 30 seconds.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Pygments lexer for GW-BASIC."""
|
|
2
|
+
|
|
3
|
+
from pygments.lexer import RegexLexer
|
|
4
|
+
from pygments.token import (
|
|
5
|
+
Comment, Keyword, Name, Number, Operator, Punctuation, String, Text,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GWBasicLexer(RegexLexer):
|
|
10
|
+
name = 'GW-BASIC'
|
|
11
|
+
aliases = ['gwbasic', 'basic']
|
|
12
|
+
filenames = ['*.bas', '*.BAS']
|
|
13
|
+
mimetypes = ['text/x-basic']
|
|
14
|
+
|
|
15
|
+
tokens = {
|
|
16
|
+
'root': [
|
|
17
|
+
# REM comments (to end of line)
|
|
18
|
+
(r"(?i)\bREM\b.*$", Comment.Single),
|
|
19
|
+
# Single-quote comments
|
|
20
|
+
(r"'.*$", Comment.Single),
|
|
21
|
+
|
|
22
|
+
# String literals
|
|
23
|
+
(r'"[^"]*"', String.Double),
|
|
24
|
+
|
|
25
|
+
# Line numbers at start of line
|
|
26
|
+
(r'^\s*\d+', Name.Label),
|
|
27
|
+
|
|
28
|
+
# Hex and octal literals
|
|
29
|
+
(r'&[Hh][0-9A-Fa-f]+', Number.Hex),
|
|
30
|
+
(r'&[Oo]?[0-7]+', Number.Oct),
|
|
31
|
+
|
|
32
|
+
# Floating point
|
|
33
|
+
(r'\d+\.\d*([eEdD][+-]?\d+)?[!#]?', Number.Float),
|
|
34
|
+
(r'\d+[eEdD][+-]?\d+[!#]?', Number.Float),
|
|
35
|
+
|
|
36
|
+
# Integer
|
|
37
|
+
(r'\d+[%!#]?', Number.Integer),
|
|
38
|
+
|
|
39
|
+
# Statements / keywords
|
|
40
|
+
(r'(?i)\b(AUTO|BEEP|BLOAD|BSAVE|CALL|CALLS|CHAIN|CHDIR|CIRCLE'
|
|
41
|
+
r'|CLEAR|CLOSE|CLS|COLOR|COM|COMMON|CONT|DATA|DEF\s+SEG'
|
|
42
|
+
r'|DEF\s+FN|DEFDBL|DEFINT|DEFSNG|DEFSTR|DELETE|DIM|DRAW'
|
|
43
|
+
r'|EDIT|ELSE|END|ENVIRON|ERASE|ERROR|FIELD|FILES|FOR|GET'
|
|
44
|
+
r'|GOSUB|GOTO|IF|INPUT|KEY|KILL|LCOPY|LET|LINE\s+INPUT'
|
|
45
|
+
r'|LINE|LIST|LLIST|LOAD|LOCATE|LPRINT|LSET|MERGE|MKDIR'
|
|
46
|
+
r'|MOTOR|NAME|NEW|NEXT|ON|OPEN|OPTION\s+BASE|OUT|PAINT'
|
|
47
|
+
r'|PALETTE|PLAY|POKE|PRESET|PRINT|PSET|PUT|RANDOMIZE'
|
|
48
|
+
r'|READ|REM|RENUM|RESET|RESTORE|RESUME|RETURN|RMDIR|RSET'
|
|
49
|
+
r'|RUN|SAVE|SCREEN|SHELL|SOUND|STOP|SWAP|SYSTEM|THEN|TIMER'
|
|
50
|
+
r'|TO|TRON|TROFF|USING|VIEW|WAIT|WEND|WHILE|WIDTH|WINDOW'
|
|
51
|
+
r'|WRITE)\b', Keyword),
|
|
52
|
+
|
|
53
|
+
# Built-in functions
|
|
54
|
+
(r'(?i)\b(ABS|ASC|ATN|CDBL|CHR\$|CINT|COS|CSNG|CSRLIN'
|
|
55
|
+
r'|CVD|CVI|CVS|DATE\$|EOF|ENVIRON\$|ERDEV\$?|ERL|ERR'
|
|
56
|
+
r'|EXP|FIX|FN|FRE|HEX\$|INKEY\$|INP|INPUT\$|INSTR|INT'
|
|
57
|
+
r'|IOCTL\$|LEFT\$|LEN|LOC|LOF|LOG|LPOS|MID\$|MKD\$'
|
|
58
|
+
r'|MKI\$|MKS\$|OCT\$|PEEK|PEN|PMAP|POINT|POS|RIGHT\$'
|
|
59
|
+
r'|RND|SGN|SIN|SPACE\$|SPC|SQR|STICK|STR\$|STRIG'
|
|
60
|
+
r'|STRING\$|TAB|TAN|TIME\$|TIMER|USR|VAL|VARPTR\$?)\b',
|
|
61
|
+
Name.Builtin),
|
|
62
|
+
|
|
63
|
+
# Logical / arithmetic operators as keywords
|
|
64
|
+
(r'(?i)\b(AND|EQV|IMP|MOD|NOT|OR|XOR|STEP)\b', Operator.Word),
|
|
65
|
+
|
|
66
|
+
# Operators
|
|
67
|
+
(r'[+\-*/\\^<>=]', Operator),
|
|
68
|
+
(r'<>|<=|>=', Operator),
|
|
69
|
+
|
|
70
|
+
# Punctuation
|
|
71
|
+
(r'[(),;:#]', Punctuation),
|
|
72
|
+
|
|
73
|
+
# Identifiers (variable names)
|
|
74
|
+
(r'[A-Za-z][A-Za-z0-9]*[%!#$]?', Name),
|
|
75
|
+
|
|
76
|
+
# Whitespace
|
|
77
|
+
(r'\s+', Text),
|
|
78
|
+
],
|
|
79
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Install the GW-BASIC kernel into Jupyter."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import shutil
|
|
6
|
+
import sys
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def install_kernel(user=True, prefix=None, gwbasic=None):
|
|
12
|
+
from jupyter_client.kernelspec import KernelSpecManager
|
|
13
|
+
|
|
14
|
+
spec = json.loads((Path(__file__).parent / 'kernel.json').read_text())
|
|
15
|
+
spec['argv'][0] = sys.executable
|
|
16
|
+
if gwbasic is not None:
|
|
17
|
+
binary = shutil.which(str(gwbasic))
|
|
18
|
+
if binary is None:
|
|
19
|
+
raise ValueError(f'GW-BASIC executable not found: {gwbasic}')
|
|
20
|
+
spec['env'] = {'GWBASIC': str(Path(binary).absolute())}
|
|
21
|
+
|
|
22
|
+
with tempfile.TemporaryDirectory() as td:
|
|
23
|
+
dest = Path(td) / 'gwbasic'
|
|
24
|
+
dest.mkdir()
|
|
25
|
+
(dest / 'kernel.json').write_text(json.dumps(spec, indent=2) + '\n')
|
|
26
|
+
|
|
27
|
+
ksm = KernelSpecManager()
|
|
28
|
+
ksm.install_kernel_spec(
|
|
29
|
+
str(dest), kernel_name='gwbasic', user=user, prefix=prefix,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
print('GW-BASIC kernel installed successfully.')
|
|
33
|
+
print('Run "jupyter kernelspec list" to verify.')
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def main():
|
|
37
|
+
parser = argparse.ArgumentParser(description='Install the GW-BASIC Jupyter kernel')
|
|
38
|
+
location = parser.add_mutually_exclusive_group()
|
|
39
|
+
location.add_argument('--user', action='store_true',
|
|
40
|
+
help='Install for the current user (default)')
|
|
41
|
+
location.add_argument('--sys-prefix', action='store_true',
|
|
42
|
+
help='Install into sys.prefix (for virtualenvs)')
|
|
43
|
+
location.add_argument('--prefix', type=str, default=None,
|
|
44
|
+
help='Install into a specific prefix')
|
|
45
|
+
parser.add_argument('--gwbasic', help='Interpreter executable to save in the kernelspec')
|
|
46
|
+
args = parser.parse_args()
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
if args.sys_prefix:
|
|
50
|
+
install_kernel(user=False, prefix=sys.prefix, gwbasic=args.gwbasic)
|
|
51
|
+
elif args.prefix:
|
|
52
|
+
install_kernel(user=False, prefix=args.prefix, gwbasic=args.gwbasic)
|
|
53
|
+
else:
|
|
54
|
+
install_kernel(gwbasic=args.gwbasic)
|
|
55
|
+
except ValueError as exc:
|
|
56
|
+
parser.error(str(exc))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == '__main__':
|
|
60
|
+
main()
|