CI: fix dos-cross-compile env; codegen: accept concat in CVI/CVS/CVD/cmp
- .github/workflows/ci.yml: the dos-cross-compile job failed on the first push because build_dos.sh sources $HOME/openwatcom-v2/setvars.sh if WATCOM is unset, but that file isn't part of the OpenWatcom V2 snapshot — I'd been creating it locally by hand. Add a "Configure OpenWatcom env" step that generates setvars.sh after extraction (so build_dos.sh works) AND exports WATCOM/PATH/INCLUDE via $GITHUB_ENV (so subsequent steps work even if setvars.sh sourcing changes). Also stash both DOS binaries before the next-mode clean wipes them, so the artifact upload actually has both .exe files. - src/codegen.c: switch the four remaining emit_str_atom callers (CVI/CVS/CVD function args + string-comparison left/right) to emit_str_expr. Now `CVS(A$+B$)` and `A$+B$ < C$` accept concatenation in their string operands; previously the atom-level caller stopped at the first identifier and the trailing `+` confused downstream parsing. Verified: CVS(MKS$(3.14)+MKS$(0)) round-trips to 3.14 in both interpreter and compiled binary. All 72 interpreter + 63 compiler tests still pass. - docs/getting-started.md: document that gwbasic-compile auto-numbers unnumbered direct-mode lines (last_num + 10) so scratchpad-style programs compile without manual renumbering. - tests/run_freedos_qemu.sh: helper for going through the manual TUI checklist on bare FreeDOS. Modern qemu-kvm doesn't expose -fda on the default machine type and fat:rw: protocol is gone, so a fully automated FreeDOS smoke isn't tractable from userspace; this script builds a FAT data image (mtools), attaches it as -hdb to the FreeDOS qcow2, and points the user at the manual sequence in the script header. The DOSBox-X harness (run_dos_smoke.sh) remains the automated DOS smoke.
This commit is contained in:
+33
-15
@@ -51,33 +51,51 @@ jobs:
|
||||
tar -xJf /tmp/ow-snapshot.tar.xz -C ~/openwatcom-v2
|
||||
rm -f /tmp/ow-snapshot.tar.xz
|
||||
|
||||
- name: Configure OpenWatcom env
|
||||
run: |
|
||||
# Generate the setvars.sh that build_dos.sh sources automatically.
|
||||
# The cache step skips its creation step so this also runs on
|
||||
# cache hits; -f overwrites without complaint.
|
||||
cat > ~/openwatcom-v2/setvars.sh <<'EOF'
|
||||
export WATCOM=$HOME/openwatcom-v2
|
||||
export PATH=$WATCOM/binl64:$WATCOM/binl:$PATH
|
||||
export EDPATH=$WATCOM/eddat
|
||||
export INCLUDE=$WATCOM/h
|
||||
EOF
|
||||
chmod +x ~/openwatcom-v2/setvars.sh
|
||||
# Also export to subsequent steps directly so a missing
|
||||
# setvars.sh on a future runner doesn't silently break the build.
|
||||
{
|
||||
echo "WATCOM=$HOME/openwatcom-v2"
|
||||
echo "EDPATH=$HOME/openwatcom-v2/eddat"
|
||||
echo "INCLUDE=$HOME/openwatcom-v2/h"
|
||||
} >> "$GITHUB_ENV"
|
||||
echo "$HOME/openwatcom-v2/binl64" >> "$GITHUB_PATH"
|
||||
echo "$HOME/openwatcom-v2/binl" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build 16-bit DOS target
|
||||
run: ./build_dos.sh 16
|
||||
run: |
|
||||
./build_dos.sh 16
|
||||
mkdir -p .ci-stash
|
||||
cp gwbasic16.exe .ci-stash/
|
||||
|
||||
- name: Build 32-bit DOS target
|
||||
run: |
|
||||
./build_dos.sh clean
|
||||
./build_dos.sh 32
|
||||
cp gwbasic.exe .ci-stash/
|
||||
|
||||
- name: Verify binary sizes look sane
|
||||
run: |
|
||||
test -f gwbasic.exe
|
||||
# 32-bit LE executable; should be a few hundred KB
|
||||
size=$(stat -c%s gwbasic.exe)
|
||||
echo "gwbasic.exe = $size bytes"
|
||||
[ "$size" -gt 100000 ] && [ "$size" -lt 500000 ]
|
||||
# Rebuild 16-bit too for the artifact upload
|
||||
./build_dos.sh clean
|
||||
./build_dos.sh 16
|
||||
test -f gwbasic16.exe
|
||||
size16=$(stat -c%s gwbasic16.exe)
|
||||
size16=$(stat -c%s .ci-stash/gwbasic16.exe)
|
||||
size32=$(stat -c%s .ci-stash/gwbasic.exe)
|
||||
echo "gwbasic16.exe = $size16 bytes"
|
||||
[ "$size16" -gt 80000 ] && [ "$size16" -lt 200000 ]
|
||||
echo "gwbasic.exe = $size32 bytes"
|
||||
[ "$size16" -gt 80000 ] && [ "$size16" -lt 200000 ]
|
||||
[ "$size32" -gt 100000 ] && [ "$size32" -lt 500000 ]
|
||||
|
||||
- name: Upload DOS artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dos-binaries
|
||||
path: |
|
||||
gwbasic16.exe
|
||||
gwbasic.exe
|
||||
path: .ci-stash/*.exe
|
||||
|
||||
@@ -102,6 +102,12 @@ build/gwbasic-compile program.bas
|
||||
build/gwbasic-compile -c --runtime . program.bas
|
||||
```
|
||||
|
||||
Both numbered (`10 PRINT "HI"`) and unnumbered (`PRINT "HI"`) sources
|
||||
compile. Unnumbered lines get auto-assigned numbers (10, 20, 30, ...) so
|
||||
the analysis pass and codegen can produce labeled statements; explicit
|
||||
line numbers are preserved. Direct-mode scratchpad scripts and classic
|
||||
"just a list of statements" programs compile without manual renumbering.
|
||||
|
||||
### Compiler Options
|
||||
|
||||
```
|
||||
|
||||
+8
-7
@@ -486,19 +486,19 @@ static void emit_atom(void)
|
||||
if (xfunc == XFUNC_CVI) {
|
||||
EMIT("gw_fn_cvi(&(gw_value_t){.type=VT_STR,.sval=");
|
||||
if (cur() == '(') advance();
|
||||
emit_str_atom();
|
||||
emit_str_expr();
|
||||
if (cur() == ')') advance();
|
||||
EMIT("}).ival");
|
||||
} else if (xfunc == XFUNC_CVS) {
|
||||
EMIT("gw_fn_cvs(&(gw_value_t){.type=VT_STR,.sval=");
|
||||
if (cur() == '(') advance();
|
||||
emit_str_atom();
|
||||
emit_str_expr();
|
||||
if (cur() == ')') advance();
|
||||
EMIT("}).fval");
|
||||
} else if (xfunc == XFUNC_CVD) {
|
||||
EMIT("gw_fn_cvd(&(gw_value_t){.type=VT_STR,.sval=");
|
||||
if (cur() == '(') advance();
|
||||
emit_str_atom();
|
||||
emit_str_expr();
|
||||
if (cur() == ')') advance();
|
||||
EMIT("}).dval");
|
||||
} else {
|
||||
@@ -823,20 +823,21 @@ static void emit_num_prec(int min_prec)
|
||||
/* For string comparisons, emit strcmp-based code */
|
||||
bool is_relational = cop || op == TOK_GT || op == TOK_LT || op == TOK_EQ;
|
||||
if (is_relational && left_type == VT_STR) {
|
||||
/* Re-emit left as string (it was emitted as numeric atom) */
|
||||
/* Re-emit left as a full string expression (was emitted as numeric
|
||||
* atom); emit_str_expr stops at the comparison op since it only
|
||||
* consumes TOK_PLUS. */
|
||||
uint8_t *save_tp = tp;
|
||||
tp = left_start;
|
||||
char *left_str;
|
||||
{ FILE *orig = out; char *buf = NULL; size_t sz = 0;
|
||||
out = open_memstream(&buf, &sz);
|
||||
emit_str_atom();
|
||||
emit_str_expr();
|
||||
fclose(out); out = orig; left_str = buf; }
|
||||
tp = save_tp;
|
||||
/* Buffer right as string expression */
|
||||
char *right_str;
|
||||
{ FILE *orig = out; char *buf = NULL; size_t sz = 0;
|
||||
out = open_memstream(&buf, &sz);
|
||||
emit_str_atom();
|
||||
emit_str_expr();
|
||||
fclose(out); out = orig; right_str = buf; }
|
||||
const char *cmpop = cop ? cop : binop_c(op);
|
||||
char *combined = NULL; size_t csz = 0;
|
||||
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
# Launch a FreeDOS 1.4 QEMU VM with gwbasic16.exe and the smoke test on a
|
||||
# FAT disk image, for manual verification of the BIOS-rendered TUI.
|
||||
#
|
||||
# Usage: bash tests/run_freedos_qemu.sh
|
||||
#
|
||||
# The script is *not* a self-contained automated smoke test — DOS doesn't
|
||||
# pipe console input cleanly enough through QEMU's -serial stdio for that
|
||||
# to be reliable, and modern qemu-kvm builds don't expose -fda on the
|
||||
# default machine type. Use tests/run_dos_smoke.sh (DOSBox-X) for the
|
||||
# automated smoke; this script is for going through the manual TUI
|
||||
# checklist in docs/getting-started.md against bare FreeDOS.
|
||||
#
|
||||
# Once FreeDOS boots, press a key to skip the boot menu (or wait for the
|
||||
# default), then at the C:\> prompt:
|
||||
#
|
||||
# C:\> D:
|
||||
# D:\> DIR (sanity-check the FAT image is mounted)
|
||||
# D:\> GWBASIC.EXE SMOKE.BAS (runs the non-interactive smoke)
|
||||
# D:\> TYPE OUT.TXT (compare against tests/expected/dos_smoke.expected)
|
||||
# D:\> GWBASIC.EXE (no args -- exercises the TUI editor)
|
||||
#
|
||||
# Quit QEMU: Ctrl-Alt-G then close the window, or in -nographic mode use
|
||||
# the QEMU monitor (Ctrl-A then X).
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
EXE="$PROJECT_DIR/gwbasic16.exe"
|
||||
SMOKE="$SCRIPT_DIR/dos_smoke.bas"
|
||||
FREEDOS_IMG="${FREEDOS_IMG:-$HOME/DOS/images/freedos.qcow2}"
|
||||
QEMU="${QEMU:-/usr/libexec/qemu-kvm}"
|
||||
DATA_IMG="$HOME/.cache/gw-basic-2026/freedos_d.img"
|
||||
|
||||
if [ ! -x "$EXE" ]; then
|
||||
echo "ERROR: $EXE not found. Run ./build_dos.sh 16 first." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$FREEDOS_IMG" ]; then
|
||||
echo "ERROR: FreeDOS qcow2 not found at $FREEDOS_IMG." >&2
|
||||
echo "Override with FREEDOS_IMG=/path/to/freedos.qcow2" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -x "$QEMU" ]; then
|
||||
echo "ERROR: qemu-kvm not found at $QEMU. Override with QEMU=/path/to/qemu" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Building FAT data image at $DATA_IMG"
|
||||
mkdir -p "$(dirname "$DATA_IMG")"
|
||||
dd if=/dev/zero of="$DATA_IMG" bs=1M count=8 status=none
|
||||
mkfs.vfat "$DATA_IMG" >/dev/null
|
||||
mcopy -i "$DATA_IMG" "$EXE" ::GWBASIC.EXE
|
||||
mcopy -i "$DATA_IMG" "$SMOKE" ::SMOKE.BAS
|
||||
sed 's/$/\r/' "$SMOKE" > /tmp/_smoke_crlf.bas
|
||||
mcopy -i "$DATA_IMG" -o /tmp/_smoke_crlf.bas ::SMOKE.BAS
|
||||
rm -f /tmp/_smoke_crlf.bas
|
||||
mdir -i "$DATA_IMG"
|
||||
|
||||
echo
|
||||
echo "==> Launching FreeDOS QEMU. See header of $0 for the manual test sequence."
|
||||
echo "==> Quit: Ctrl-Alt-G, close window. Press Enter to continue."
|
||||
read -r
|
||||
|
||||
exec "$QEMU" \
|
||||
-machine pc \
|
||||
-cpu max \
|
||||
-m 32 \
|
||||
-hda "$FREEDOS_IMG" \
|
||||
-hdb "$DATA_IMG" \
|
||||
-nic none \
|
||||
-boot c \
|
||||
-display gtk \
|
||||
-rtc base=localtime
|
||||
Reference in New Issue
Block a user