BASIC is starting to work.
This commit is contained in:
parent
f62b89fc02
commit
b3cc66be4b
9 changed files with 699 additions and 3 deletions
8
Makefile
8
Makefile
|
|
@ -3,9 +3,9 @@
|
|||
# Builds the full DVX stack: core library, task switcher,
|
||||
# bootstrap loader, text help library, widgets, shell, and apps.
|
||||
|
||||
.PHONY: all clean core tasks loader texthelp listhelp widgets shell taskmgr serial apps tools
|
||||
.PHONY: all clean core tasks loader texthelp listhelp widgets shell taskmgr serial dvxbasic apps tools
|
||||
|
||||
all: core tasks loader texthelp listhelp widgets shell taskmgr serial apps tools
|
||||
all: core tasks loader texthelp listhelp widgets shell taskmgr serial dvxbasic apps tools
|
||||
|
||||
core:
|
||||
$(MAKE) -C core
|
||||
|
|
@ -34,6 +34,9 @@ taskmgr: shell
|
|||
serial: core tasks
|
||||
$(MAKE) -C serial
|
||||
|
||||
dvxbasic: core tasks shell tools
|
||||
$(MAKE) -C dvxbasic
|
||||
|
||||
tools:
|
||||
$(MAKE) -C tools
|
||||
|
||||
|
|
@ -50,6 +53,7 @@ clean:
|
|||
$(MAKE) -C shell clean
|
||||
$(MAKE) -C taskmgr clean
|
||||
$(MAKE) -C serial clean
|
||||
$(MAKE) -C dvxbasic clean
|
||||
$(MAKE) -C apps clean
|
||||
$(MAKE) -C tools clean
|
||||
-rmdir obj 2>/dev/null
|
||||
|
|
|
|||
2
config/basrt.dep
Normal file
2
config/basrt.dep
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
libtasks
|
||||
libdvx
|
||||
|
|
@ -2315,6 +2315,7 @@ extern unsigned long long __umoddi3(unsigned long long, unsigned long long);
|
|||
extern void __dj_assert(const char *, const char *, int);
|
||||
extern unsigned short __dj_ctype_flags[];
|
||||
extern unsigned char __dj_ctype_tolower[];
|
||||
extern unsigned char __dj_ctype_toupper[];
|
||||
|
||||
// GCC emulated thread-local storage
|
||||
extern void *__emutls_get_address(void *);
|
||||
|
|
@ -2424,6 +2425,7 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
DXE_EXPORT(strcspn)
|
||||
{ "_strdup", (void *)dvxStrdup },
|
||||
DXE_EXPORT(strerror)
|
||||
DXE_EXPORT(strnicmp)
|
||||
DXE_EXPORT(stricmp)
|
||||
DXE_EXPORT(strlen)
|
||||
DXE_EXPORT(strncasecmp)
|
||||
|
|
@ -2439,6 +2441,7 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
// --- ctype ---
|
||||
DXE_EXPORT(isalnum)
|
||||
DXE_EXPORT(isalpha)
|
||||
DXE_EXPORT(isascii)
|
||||
DXE_EXPORT(isdigit)
|
||||
DXE_EXPORT(islower)
|
||||
DXE_EXPORT(isprint)
|
||||
|
|
@ -2451,6 +2454,7 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
|
||||
// --- conversion ---
|
||||
DXE_EXPORT(abs)
|
||||
DXE_EXPORT(ldiv)
|
||||
DXE_EXPORT(atof)
|
||||
DXE_EXPORT(atoi)
|
||||
DXE_EXPORT(atol)
|
||||
|
|
@ -2461,6 +2465,7 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
|
||||
// --- formatted I/O ---
|
||||
DXE_EXPORT(fprintf)
|
||||
DXE_EXPORT(perror)
|
||||
DXE_EXPORT(fputs)
|
||||
DXE_EXPORT(fscanf)
|
||||
DXE_EXPORT(printf)
|
||||
|
|
@ -2521,13 +2526,19 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
DXE_EXPORT(localtime)
|
||||
DXE_EXPORT(mktime)
|
||||
DXE_EXPORT(strftime)
|
||||
DXE_EXPORT(asctime)
|
||||
DXE_EXPORT(ctime)
|
||||
DXE_EXPORT(sleep)
|
||||
DXE_EXPORT(time)
|
||||
DXE_EXPORT(usleep)
|
||||
|
||||
// --- process / environment ---
|
||||
DXE_EXPORT(abort)
|
||||
DXE_EXPORT(atexit)
|
||||
DXE_EXPORT(exit)
|
||||
DXE_EXPORT(getenv)
|
||||
DXE_EXPORT(setenv)
|
||||
DXE_EXPORT(putenv)
|
||||
DXE_EXPORT(system)
|
||||
|
||||
// --- sorting / searching ---
|
||||
|
|
@ -2541,6 +2552,7 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
// --- setjmp / signal ---
|
||||
DXE_EXPORT(longjmp)
|
||||
DXE_EXPORT(setjmp)
|
||||
DXE_EXPORT(raise)
|
||||
DXE_EXPORT(signal)
|
||||
|
||||
// --- libm ---
|
||||
|
|
@ -2561,7 +2573,11 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
DXE_EXPORT(modf)
|
||||
DXE_EXPORT(pow)
|
||||
DXE_EXPORT(sin)
|
||||
DXE_EXPORT(sinh)
|
||||
DXE_EXPORT(cosh)
|
||||
DXE_EXPORT(tanh)
|
||||
DXE_EXPORT(sqrt)
|
||||
DXE_EXPORT(strtof)
|
||||
DXE_EXPORT(tan)
|
||||
|
||||
// --- errno ---
|
||||
|
|
@ -2582,6 +2598,7 @@ DXE_EXPORT_TABLE(sDxeExportTable)
|
|||
DXE_EXPORT(__dj_assert)
|
||||
DXE_EXPORT(__dj_ctype_flags)
|
||||
DXE_EXPORT(__dj_ctype_tolower)
|
||||
DXE_EXPORT(__dj_ctype_toupper)
|
||||
DXE_EXPORT(__djgpp_exception_state_ptr)
|
||||
|
||||
// --- GCC internals ---
|
||||
|
|
|
|||
89
dvxbasic/Makefile
Normal file
89
dvxbasic/Makefile
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# DVX BASIC Makefile for DJGPP cross-compilation
|
||||
#
|
||||
# Builds:
|
||||
# basrt.lib -- BASIC runtime library (VM + values + dlregsym init)
|
||||
# dvxbasic.app -- BASIC IDE (compiler + UI, links against basrt.lib)
|
||||
#
|
||||
# The runtime is a separate library so compiled BASIC apps can use
|
||||
# it without including the compiler. The library's constructor calls
|
||||
# dlregsym() to register its exports, making them available to DXEs
|
||||
# loaded later (apps, widgets, etc.).
|
||||
|
||||
DJGPP_PREFIX = $(HOME)/djgpp/djgpp
|
||||
CC = $(DJGPP_PREFIX)/bin/i586-pc-msdosdjgpp-gcc
|
||||
DXE3GEN = PATH=$(DJGPP_PREFIX)/bin:$(PATH) DJDIR=$(DJGPP_PREFIX)/i586-pc-msdosdjgpp $(DJGPP_PREFIX)/i586-pc-msdosdjgpp/bin/dxe3gen
|
||||
CFLAGS = -O2 -Wall -Wextra -march=i486 -mtune=i586 -I../core -I../core/platform -I../widgets -I../shell -I../tasks -I../core/thirdparty -I.
|
||||
|
||||
OBJDIR = ../obj/dvxbasic
|
||||
LIBSDIR = ../bin/libs
|
||||
APPDIR = ../bin/apps/dvxbasic
|
||||
DVXRES = ../bin/dvxres
|
||||
SAMPLES = samples/hello.bas
|
||||
|
||||
# Runtime library objects (VM + values)
|
||||
RT_OBJS = $(OBJDIR)/vm.o $(OBJDIR)/values.o
|
||||
RT_TARGET = $(LIBSDIR)/basrt.lib
|
||||
|
||||
# Compiler objects (only needed by the IDE)
|
||||
COMP_OBJS = $(OBJDIR)/lexer.o $(OBJDIR)/parser.o $(OBJDIR)/codegen.o $(OBJDIR)/symtab.o
|
||||
|
||||
# IDE app objects
|
||||
APP_OBJS = $(OBJDIR)/ideMain.o
|
||||
APP_TARGET = $(APPDIR)/dvxbasic.app
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(RT_TARGET) $(LIBSDIR)/basrt.dep $(APP_TARGET) install-samples
|
||||
|
||||
# Runtime library DXE (exports symbols via dlregsym constructor)
|
||||
$(RT_TARGET): $(RT_OBJS) | $(LIBSDIR)
|
||||
$(DXE3GEN) -o $(LIBSDIR)/basrt.dxe \
|
||||
-E _bas -E _BAS \
|
||||
-U $(RT_OBJS)
|
||||
mv $(LIBSDIR)/basrt.dxe $@
|
||||
|
||||
$(LIBSDIR)/basrt.dep: ../config/basrt.dep | $(LIBSDIR)
|
||||
sed 's/$$/\r/' $< > $@
|
||||
|
||||
# IDE app DXE (compiler linked in, runtime from basrt.lib)
|
||||
$(APP_TARGET): $(COMP_OBJS) $(APP_OBJS) dvxbasic.res | $(APPDIR)
|
||||
$(DXE3GEN) -o $@ -E _appDescriptor -E _appMain -U $(COMP_OBJS) $(APP_OBJS)
|
||||
$(DVXRES) build $@ dvxbasic.res
|
||||
|
||||
install-samples: $(SAMPLES) | $(APPDIR)
|
||||
cp $(SAMPLES) $(APPDIR)/
|
||||
|
||||
# Object files
|
||||
$(OBJDIR)/codegen.o: compiler/codegen.c compiler/codegen.h compiler/opcodes.h runtime/values.h | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/ideMain.o: ide/ideMain.c compiler/parser.h runtime/vm.h | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/lexer.o: compiler/lexer.c compiler/lexer.h | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/parser.o: compiler/parser.c compiler/parser.h compiler/lexer.h compiler/codegen.h compiler/symtab.h compiler/opcodes.h | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/symtab.o: compiler/symtab.c compiler/symtab.h compiler/opcodes.h | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/values.o: runtime/values.c runtime/values.h compiler/opcodes.h | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/vm.o: runtime/vm.c runtime/vm.h runtime/values.h compiler/opcodes.h | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
# Directories
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
$(LIBSDIR):
|
||||
mkdir -p $(LIBSDIR)
|
||||
|
||||
$(APPDIR):
|
||||
mkdir -p $(APPDIR)
|
||||
|
||||
clean:
|
||||
rm -f $(RT_OBJS) $(COMP_OBJS) $(APP_OBJS) $(RT_TARGET) $(APP_TARGET) $(LIBSDIR)/basrt.dep $(OBJDIR)/basrt_init.o
|
||||
5
dvxbasic/dvxbasic.res
Normal file
5
dvxbasic/dvxbasic.res
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# dvxbasic.res -- Resource manifest for DVX BASIC
|
||||
icon32 icon icon32.bmp
|
||||
name text "DVX BASIC"
|
||||
author text "DVX Project"
|
||||
description text "BASIC language IDE and runtime"
|
||||
BIN
dvxbasic/icon32.bmp
(Stored with Git LFS)
Normal file
BIN
dvxbasic/icon32.bmp
(Stored with Git LFS)
Normal file
Binary file not shown.
496
dvxbasic/ide/ideMain.c
Normal file
496
dvxbasic/ide/ideMain.c
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
// ideMain.c -- DVX BASIC Runner application
|
||||
//
|
||||
// A DVX app that loads, compiles, and runs BASIC programs.
|
||||
// PRINT output goes to a scrollable TextArea widget. Compile
|
||||
// errors are displayed with line numbers.
|
||||
//
|
||||
// This is Phase 3 of DVX BASIC: proving the compiler and VM
|
||||
// work on real hardware inside the DVX windowing system.
|
||||
|
||||
#include "dvxApp.h"
|
||||
#include "dvxDialog.h"
|
||||
#include "dvxWidget.h"
|
||||
#include "dvxWm.h"
|
||||
#include "shellApp.h"
|
||||
#include "widgetBox.h"
|
||||
#include "widgetButton.h"
|
||||
#include "widgetLabel.h"
|
||||
#include "widgetTextInput.h"
|
||||
#include "widgetStatusBar.h"
|
||||
|
||||
#include "../compiler/parser.h"
|
||||
#include "../runtime/vm.h"
|
||||
#include "../runtime/values.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// ============================================================
|
||||
// Constants
|
||||
// ============================================================
|
||||
|
||||
#define IDE_WIN_W 560
|
||||
#define IDE_WIN_H 400
|
||||
#define IDE_BTN_W 80
|
||||
#define IDE_BTN_SPACING 8
|
||||
#define IDE_MAX_SOURCE 65536
|
||||
#define IDE_MAX_OUTPUT 32768
|
||||
|
||||
// Menu command IDs
|
||||
#define CMD_OPEN 100
|
||||
#define CMD_RUN 101
|
||||
#define CMD_STOP 102
|
||||
#define CMD_CLEAR 103
|
||||
#define CMD_EXIT 104
|
||||
|
||||
// ============================================================
|
||||
// Prototypes
|
||||
// ============================================================
|
||||
|
||||
int32_t appMain(DxeAppContextT *ctx);
|
||||
static void buildWindow(void);
|
||||
static void clearOutput(void);
|
||||
static void compileAndRun(void);
|
||||
static void loadFile(void);
|
||||
static void onClose(WindowT *win);
|
||||
static void onMenu(WindowT *win, int32_t menuId);
|
||||
static void onOpenClick(WidgetT *w);
|
||||
static void onRunClick(WidgetT *w);
|
||||
static void onClearClick(WidgetT *w);
|
||||
static void printCallback(void *ctx, const char *text, bool newline);
|
||||
static bool inputCallback(void *ctx, const char *prompt, char *buf, int32_t bufSize);
|
||||
static bool doEventsCallback(void *ctx);
|
||||
static void setStatus(const char *text);
|
||||
|
||||
// ============================================================
|
||||
// Module state
|
||||
// ============================================================
|
||||
|
||||
static DxeAppContextT *sCtx = NULL;
|
||||
static AppContextT *sAc = NULL;
|
||||
static WindowT *sWin = NULL;
|
||||
static WidgetT *sEditor = NULL; // TextArea for source code
|
||||
static WidgetT *sOutput = NULL; // TextArea for program output
|
||||
static WidgetT *sStatus = NULL; // Status bar label
|
||||
static BasVmT *sVm = NULL; // VM instance (non-NULL while running)
|
||||
|
||||
static char sSourceBuf[IDE_MAX_SOURCE];
|
||||
static char sOutputBuf[IDE_MAX_OUTPUT];
|
||||
static int32_t sOutputLen = 0;
|
||||
static char sFilePath[260];
|
||||
|
||||
// ============================================================
|
||||
// App descriptor
|
||||
// ============================================================
|
||||
|
||||
AppDescriptorT appDescriptor = {
|
||||
.name = "DVX BASIC",
|
||||
.hasMainLoop = false,
|
||||
.multiInstance = false,
|
||||
.stackSize = SHELL_STACK_DEFAULT,
|
||||
.priority = 0
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// appMain
|
||||
// ============================================================
|
||||
|
||||
int32_t appMain(DxeAppContextT *ctx) {
|
||||
sCtx = ctx;
|
||||
sAc = ctx->shellCtx;
|
||||
|
||||
basStringSystemInit();
|
||||
buildWindow();
|
||||
|
||||
sFilePath[0] = '\0';
|
||||
sSourceBuf[0] = '\0';
|
||||
sOutputBuf[0] = '\0';
|
||||
sOutputLen = 0;
|
||||
|
||||
setStatus("Ready. Open a .BAS file or type code and press Run.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// buildWindow
|
||||
// ============================================================
|
||||
|
||||
static void buildWindow(void) {
|
||||
int32_t winX = (sAc->display.width - IDE_WIN_W) / 2;
|
||||
int32_t winY = (sAc->display.height - IDE_WIN_H) / 4;
|
||||
|
||||
sWin = dvxCreateWindow(sAc, "DVX BASIC", winX, winY, IDE_WIN_W, IDE_WIN_H, true);
|
||||
|
||||
if (!sWin) {
|
||||
return;
|
||||
}
|
||||
|
||||
sWin->onClose = onClose;
|
||||
sWin->onMenu = onMenu;
|
||||
|
||||
// Menu bar
|
||||
MenuBarT *menuBar = wmAddMenuBar(sWin);
|
||||
MenuT *fileMenu = wmAddMenu(menuBar, "&File");
|
||||
wmAddMenuItem(fileMenu, "&Open...\tCtrl+O", CMD_OPEN);
|
||||
wmAddMenuSeparator(fileMenu);
|
||||
wmAddMenuItem(fileMenu, "E&xit", CMD_EXIT);
|
||||
|
||||
MenuT *runMenu = wmAddMenu(menuBar, "&Run");
|
||||
wmAddMenuItem(runMenu, "&Run\tF5", CMD_RUN);
|
||||
wmAddMenuSeparator(runMenu);
|
||||
wmAddMenuItem(runMenu, "&Clear Output", CMD_CLEAR);
|
||||
|
||||
AccelTableT *accel = dvxCreateAccelTable();
|
||||
dvxAddAccel(accel, 'O', ACCEL_CTRL, CMD_OPEN);
|
||||
dvxAddAccel(accel, KEY_F5, 0, CMD_RUN);
|
||||
sWin->accelTable = accel;
|
||||
|
||||
// Widget tree
|
||||
WidgetT *root = wgtInitWindow(sAc, sWin);
|
||||
|
||||
// Source code editor (top half)
|
||||
WidgetT *editorFrame = wgtFrame(root, "Source");
|
||||
editorFrame->weight = 100;
|
||||
sEditor = wgtTextArea(editorFrame, IDE_MAX_SOURCE);
|
||||
sEditor->weight = 100;
|
||||
|
||||
// Button bar
|
||||
WidgetT *btnRow = wgtHBox(root);
|
||||
btnRow->spacing = wgtPixels(IDE_BTN_SPACING);
|
||||
|
||||
WidgetT *openBtn = wgtButton(btnRow, "&Open...");
|
||||
openBtn->onClick = onOpenClick;
|
||||
openBtn->prefW = wgtPixels(IDE_BTN_W);
|
||||
|
||||
WidgetT *runBtn = wgtButton(btnRow, "&Run");
|
||||
runBtn->onClick = onRunClick;
|
||||
runBtn->prefW = wgtPixels(IDE_BTN_W);
|
||||
|
||||
WidgetT *clearBtn = wgtButton(btnRow, "&Clear");
|
||||
clearBtn->onClick = onClearClick;
|
||||
clearBtn->prefW = wgtPixels(IDE_BTN_W);
|
||||
|
||||
// Output area (bottom half)
|
||||
WidgetT *outputFrame = wgtFrame(root, "Output");
|
||||
outputFrame->weight = 100;
|
||||
sOutput = wgtTextArea(outputFrame, IDE_MAX_OUTPUT);
|
||||
sOutput->weight = 100;
|
||||
sOutput->readOnly = true;
|
||||
|
||||
// Status bar
|
||||
WidgetT *statusBar = wgtStatusBar(root);
|
||||
sStatus = wgtLabel(statusBar, "");
|
||||
sStatus->weight = 100;
|
||||
|
||||
dvxFitWindow(sAc, sWin);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// clearOutput
|
||||
// ============================================================
|
||||
|
||||
static void clearOutput(void) {
|
||||
sOutputBuf[0] = '\0';
|
||||
sOutputLen = 0;
|
||||
wgtSetText(sOutput, "");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// compileAndRun
|
||||
// ============================================================
|
||||
|
||||
static void compileAndRun(void) {
|
||||
// Get source from editor
|
||||
const char *src = wgtGetText(sEditor);
|
||||
|
||||
if (!src || *src == '\0') {
|
||||
setStatus("No source code to run.");
|
||||
return;
|
||||
}
|
||||
|
||||
clearOutput();
|
||||
setStatus("Compiling...");
|
||||
|
||||
// Force a display update so the status is visible
|
||||
dvxInvalidateWindow(sAc, sWin);
|
||||
|
||||
int32_t srcLen = (int32_t)strlen(src);
|
||||
|
||||
// Compile (heap-allocated -- BasParserT is ~300KB, too large for stack)
|
||||
BasParserT *parser = (BasParserT *)malloc(sizeof(BasParserT));
|
||||
|
||||
if (!parser) {
|
||||
setStatus("Out of memory.");
|
||||
return;
|
||||
}
|
||||
|
||||
basParserInit(parser, src, srcLen);
|
||||
|
||||
if (!basParse(parser)) {
|
||||
int32_t n = snprintf(sOutputBuf, IDE_MAX_OUTPUT, "COMPILE ERROR:\n%s\n", parser->error);
|
||||
sOutputLen = n;
|
||||
wgtSetText(sOutput, sOutputBuf);
|
||||
setStatus("Compilation failed.");
|
||||
basParserFree(parser);
|
||||
free(parser);
|
||||
return;
|
||||
}
|
||||
|
||||
BasModuleT *mod = basParserBuildModule(parser);
|
||||
basParserFree(parser);
|
||||
free(parser);
|
||||
|
||||
if (!mod) {
|
||||
setStatus("Failed to build module.");
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus("Running...");
|
||||
|
||||
// Create VM
|
||||
BasVmT *vm = basVmCreate();
|
||||
basVmLoadModule(vm, mod);
|
||||
|
||||
// Set up implicit main frame
|
||||
vm->callStack[0].localCount = mod->globalCount > BAS_VM_MAX_LOCALS ? BAS_VM_MAX_LOCALS : mod->globalCount;
|
||||
vm->callDepth = 1;
|
||||
|
||||
// Set I/O callbacks
|
||||
basVmSetPrintCallback(vm, printCallback, NULL);
|
||||
basVmSetInputCallback(vm, inputCallback, NULL);
|
||||
basVmSetDoEventsCallback(vm, doEventsCallback, NULL);
|
||||
|
||||
sVm = vm;
|
||||
|
||||
// Run with step limit to prevent infinite loops from freezing the GUI
|
||||
vm->running = true;
|
||||
int32_t stepCount = 0;
|
||||
|
||||
while (vm->running) {
|
||||
BasVmResultE result = basVmStep(vm);
|
||||
|
||||
stepCount++;
|
||||
|
||||
if (result != BAS_VM_OK) {
|
||||
if (result == BAS_VM_HALTED) {
|
||||
// Normal completion
|
||||
} else {
|
||||
// Runtime error
|
||||
int32_t pos = sOutputLen;
|
||||
int32_t n = snprintf(sOutputBuf + pos, IDE_MAX_OUTPUT - pos, "\n[Runtime error: %s]\n", basVmGetError(vm));
|
||||
sOutputLen += n;
|
||||
wgtSetText(sOutput, sOutputBuf);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Yield to DVX every 10000 steps to keep the GUI responsive
|
||||
if (stepCount % 10000 == 0) {
|
||||
dvxUpdate(sAc);
|
||||
}
|
||||
}
|
||||
|
||||
sVm = NULL;
|
||||
|
||||
// Update output display
|
||||
wgtSetText(sOutput, sOutputBuf);
|
||||
|
||||
static char statusBuf[128];
|
||||
snprintf(statusBuf, sizeof(statusBuf), "Done. %ld instructions executed.", (long)stepCount);
|
||||
setStatus(statusBuf);
|
||||
|
||||
basVmDestroy(vm);
|
||||
basModuleFree(mod);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// doEventsCallback
|
||||
// ============================================================
|
||||
|
||||
static bool doEventsCallback(void *ctx) {
|
||||
(void)ctx;
|
||||
|
||||
// Update DVX display and process events
|
||||
if (sAc) {
|
||||
dvxUpdate(sAc);
|
||||
}
|
||||
|
||||
return true; // continue running
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// inputCallback
|
||||
// ============================================================
|
||||
|
||||
static bool inputCallback(void *ctx, const char *prompt, char *buf, int32_t bufSize) {
|
||||
(void)ctx;
|
||||
|
||||
// Append prompt to output
|
||||
if (prompt && sOutputLen < IDE_MAX_OUTPUT - 1) {
|
||||
int32_t n = snprintf(sOutputBuf + sOutputLen, IDE_MAX_OUTPUT - sOutputLen, "%s", prompt);
|
||||
sOutputLen += n;
|
||||
wgtSetText(sOutput, sOutputBuf);
|
||||
}
|
||||
|
||||
// Use DVX input dialog
|
||||
// For now, a simple message box prompt
|
||||
// TODO: proper INPUT dialog
|
||||
buf[0] = '\0';
|
||||
return false; // cancel for now
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// loadFile
|
||||
// ============================================================
|
||||
|
||||
static void loadFile(void) {
|
||||
FileFilterT filters[] = {
|
||||
{ "BASIC Files (*.bas)", "*.bas" },
|
||||
{ "Form Files (*.frm)", "*.frm" },
|
||||
{ "All Files (*.*)", "*.*" }
|
||||
};
|
||||
|
||||
char path[260];
|
||||
|
||||
if (dvxFileDialog(sAc, "Open BASIC File", FD_OPEN, NULL, filters, 3, path, sizeof(path))) {
|
||||
FILE *f = fopen(path, "r");
|
||||
|
||||
if (!f) {
|
||||
dvxMessageBox(sAc, "Error", "Could not open file.", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (size >= IDE_MAX_SOURCE - 1) {
|
||||
fclose(f);
|
||||
dvxMessageBox(sAc, "Error", "File too large.", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t bytesRead = (int32_t)fread(sSourceBuf, 1, size, f);
|
||||
fclose(f);
|
||||
sSourceBuf[bytesRead] = '\0';
|
||||
|
||||
wgtSetText(sEditor, sSourceBuf);
|
||||
strncpy(sFilePath, path, sizeof(sFilePath) - 1);
|
||||
sFilePath[sizeof(sFilePath) - 1] = '\0';
|
||||
|
||||
// Update window title
|
||||
char title[300];
|
||||
snprintf(title, sizeof(title), "DVX BASIC - %s", path);
|
||||
dvxSetTitle(sAc, sWin, title);
|
||||
|
||||
setStatus("File loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// onClearClick
|
||||
// ============================================================
|
||||
|
||||
static void onClearClick(WidgetT *w) {
|
||||
(void)w;
|
||||
clearOutput();
|
||||
setStatus("Output cleared.");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// onClose
|
||||
// ============================================================
|
||||
|
||||
static void onClose(WindowT *win) {
|
||||
sWin = NULL;
|
||||
sEditor = NULL;
|
||||
sOutput = NULL;
|
||||
sStatus = NULL;
|
||||
dvxDestroyWindow(sAc, win);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// onMenu
|
||||
// ============================================================
|
||||
|
||||
static void onMenu(WindowT *win, int32_t menuId) {
|
||||
(void)win;
|
||||
|
||||
switch (menuId) {
|
||||
case CMD_OPEN:
|
||||
loadFile();
|
||||
break;
|
||||
|
||||
case CMD_RUN:
|
||||
compileAndRun();
|
||||
break;
|
||||
|
||||
case CMD_CLEAR:
|
||||
clearOutput();
|
||||
break;
|
||||
|
||||
case CMD_EXIT:
|
||||
if (sWin) {
|
||||
onClose(sWin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// onOpenClick
|
||||
// ============================================================
|
||||
|
||||
static void onOpenClick(WidgetT *w) {
|
||||
(void)w;
|
||||
loadFile();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// onRunClick
|
||||
// ============================================================
|
||||
|
||||
static void onRunClick(WidgetT *w) {
|
||||
(void)w;
|
||||
compileAndRun();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// printCallback
|
||||
// ============================================================
|
||||
|
||||
static void printCallback(void *ctx, const char *text, bool newline) {
|
||||
(void)ctx;
|
||||
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t textLen = (int32_t)strlen(text);
|
||||
|
||||
// Append to output buffer
|
||||
if (sOutputLen + textLen < IDE_MAX_OUTPUT - 2) {
|
||||
memcpy(sOutputBuf + sOutputLen, text, textLen);
|
||||
sOutputLen += textLen;
|
||||
}
|
||||
|
||||
if (newline && sOutputLen < IDE_MAX_OUTPUT - 2) {
|
||||
sOutputBuf[sOutputLen++] = '\n';
|
||||
}
|
||||
|
||||
sOutputBuf[sOutputLen] = '\0';
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// setStatus
|
||||
// ============================================================
|
||||
|
||||
static void setStatus(const char *text) {
|
||||
if (sStatus) {
|
||||
wgtSetText(sStatus, text);
|
||||
}
|
||||
}
|
||||
27
dvxbasic/samples/hello.bas
Normal file
27
dvxbasic/samples/hello.bas
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
' hello.bas -- DVX BASIC Hello World
|
||||
'
|
||||
' A simple program to test the DVX BASIC runner.
|
||||
|
||||
PRINT "Hello from DVX BASIC!"
|
||||
PRINT
|
||||
PRINT "Testing arithmetic: 2 + 3 * 4 ="; 2 + 3 * 4
|
||||
PRINT "Testing strings: "; "Hello" & " " & "World"
|
||||
PRINT
|
||||
|
||||
DIM i AS INTEGER
|
||||
PRINT "Fibonacci sequence:"
|
||||
DIM a AS INTEGER
|
||||
DIM b AS INTEGER
|
||||
DIM temp AS INTEGER
|
||||
a = 0
|
||||
b = 1
|
||||
FOR i = 1 TO 15
|
||||
PRINT a;
|
||||
temp = a + b
|
||||
a = b
|
||||
b = temp
|
||||
NEXT i
|
||||
PRINT
|
||||
|
||||
PRINT
|
||||
PRINT "Done!"
|
||||
|
|
@ -194,6 +194,57 @@ static void iconImgview(void) {
|
|||
rect(5, 22, 22, 3, 60, 120, 60);
|
||||
}
|
||||
|
||||
// DVX BASIC icon: code brackets with "B" letterform
|
||||
static void iconBasic(void) {
|
||||
clear(192, 192, 192);
|
||||
|
||||
// Blue background rectangle (code editor feel)
|
||||
rect(2, 2, 28, 28, 0, 0, 128);
|
||||
|
||||
// Left bracket {
|
||||
vline(6, 6, 20, 255, 255, 0);
|
||||
hline(7, 6, 3, 255, 255, 0);
|
||||
hline(7, 25, 3, 255, 255, 0);
|
||||
hline(4, 15, 2, 255, 255, 0);
|
||||
pixel(5, 14, 255, 255, 0);
|
||||
pixel(5, 16, 255, 255, 0);
|
||||
|
||||
// "B" letter in white (bold, centered)
|
||||
// Vertical stroke
|
||||
vline(14, 7, 18, 255, 255, 255);
|
||||
|
||||
// Top horizontal
|
||||
hline(14, 7, 7, 255, 255, 255);
|
||||
hline(14, 8, 7, 255, 255, 255);
|
||||
|
||||
// Middle horizontal
|
||||
hline(14, 15, 7, 255, 255, 255);
|
||||
hline(14, 16, 7, 255, 255, 255);
|
||||
|
||||
// Bottom horizontal
|
||||
hline(14, 23, 7, 255, 255, 255);
|
||||
hline(14, 24, 7, 255, 255, 255);
|
||||
|
||||
// Right curves of B (top bump)
|
||||
vline(21, 8, 7, 255, 255, 255);
|
||||
pixel(20, 8, 255, 255, 255);
|
||||
pixel(20, 14, 255, 255, 255);
|
||||
|
||||
// Right curves of B (bottom bump)
|
||||
vline(21, 17, 6, 255, 255, 255);
|
||||
pixel(20, 17, 255, 255, 255);
|
||||
pixel(20, 23, 255, 255, 255);
|
||||
|
||||
// Right bracket }
|
||||
vline(25, 6, 20, 255, 255, 0);
|
||||
hline(22, 6, 3, 255, 255, 0);
|
||||
hline(22, 25, 3, 255, 255, 0);
|
||||
hline(26, 15, 2, 255, 255, 0);
|
||||
pixel(26, 14, 255, 255, 0);
|
||||
pixel(26, 16, 255, 255, 0);
|
||||
}
|
||||
|
||||
|
||||
static void writeBmp(const char *path) {
|
||||
int32_t rowPad = (4 - (W * 3) % 4) % 4;
|
||||
int32_t rowSize = W * 3 + rowPad;
|
||||
|
|
@ -243,7 +294,7 @@ static void writeBmp(const char *path) {
|
|||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: mkicon <output.bmp> <type>\n");
|
||||
fprintf(stderr, "Types: clock, notepad, cpanel, dvxdemo, imgview\n");
|
||||
fprintf(stderr, "Types: clock, notepad, cpanel, dvxdemo, imgview, basic\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -258,6 +309,8 @@ int main(int argc, char **argv) {
|
|||
iconCpanel();
|
||||
} else if (strcmp(type, "dvxdemo") == 0) {
|
||||
iconDvxdemo();
|
||||
} else if (strcmp(type, "basic") == 0) {
|
||||
iconBasic();
|
||||
} else if (strcmp(type, "imgview") == 0) {
|
||||
iconImgview();
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue