From 7179e632c592ac82823abe49fcd40eeccf1f8ecb Mon Sep 17 00:00:00 2001 From: Kawamata Akira Date: Mon, 6 Nov 2000 12:00:00 +0900 Subject: [PATCH] First Version Version 0.01 - from wonbe001.lzh --- keywords.h | 59 ++ makefile | 23 + test.wb | 2 + testcont.wb | 3 + testfor.wb | 11 + testgosub.wb | 19 + testif.wb | 9 + testlocate.wb | 7 + testlongloop.wb | 1 + win32text.c | 275 +++++++ win32text.h | 15 + wonbe.c | 1974 +++++++++++++++++++++++++++++++++++++++++++++++ wonbe.cf | 1 + wonbe.dsp | 112 +++ wonbe.dsw | 29 + wonbe.exe | Bin 0 -> 53248 bytes wonbe.fx | Bin 0 -> 13620 bytes wonbe.txt | 226 ++++++ 18 files changed, 2766 insertions(+) create mode 100644 keywords.h create mode 100644 makefile create mode 100644 test.wb create mode 100644 testcont.wb create mode 100644 testfor.wb create mode 100644 testgosub.wb create mode 100644 testif.wb create mode 100644 testlocate.wb create mode 100644 testlongloop.wb create mode 100644 win32text.c create mode 100644 win32text.h create mode 100644 wonbe.c create mode 100644 wonbe.cf create mode 100644 wonbe.dsp create mode 100644 wonbe.dsw create mode 100644 wonbe.exe create mode 100644 wonbe.fx create mode 100644 wonbe.txt diff --git a/keywords.h b/keywords.h new file mode 100644 index 0000000..c07a66b --- /dev/null +++ b/keywords.h @@ -0,0 +1,59 @@ +/* WONBE predefined keyword IDs */ +/* First Created: Nov.3,2000 by Nashiko */ +/* Copyright 2000 (c) by Pie Dey Co.,Ltd. */ + +#define KEYWORD_IF 0x80 +#define KEYWORD_PRINT 0x81 +#define KEYWORD_LOCATE 0x82 +#define KEYWORD_CLS 0x83 +#define KEYWORD_GOTO 0x84 +#define KEYWORD_GOSUB 0x85 +#define KEYWORD_RETURN 0x86 +#define KEYWORD_FOR 0x87 +#define KEYWORD_NEXT 0x88 +#define KEYWORD_END 0x89 +#define KEYWORD_BREAK 0x8a +#define KEYWORD_REM 0x8b +#define KEYWORD_NEW 0x8c +#define KEYWORD_LIST 0x8d +#define KEYWORD_RUN 0x8e +#define KEYWORD_CONT 0x8f +#define KEYWORD_SAVE 0x90 +#define KEYWORD_LOAD 0x91 +#define KEYWORD_MERGE 0x92 +#define KEYWORD_RANDOMIZE 0x93 +#define KEYWORD_EXIT 0x94 +#define KEYWORD_DEBUG 0x95 +#define KEYWORD_WAITVB 0x96 +#define KEYWORD_FILES 0x97 +#define KEYWORD_AND 0xa0 +#define KEYWORD_OR 0xa1 +#define KEYWORD_XOR 0xa2 +#define KEYWORD_NOT 0xb0 +#define KEYWORD_SCAN 0xc0 +#define KEYWORD_WAIT 0xc1 +#define KEYWORD_RND 0xc2 +#define KEYWORD_ABS 0xc3 +#define KEYWORD_TICK 0xc4 +#define KEYWORD_SCAN_A 0xd0 +#define KEYWORD_SCAN_B 0xd1 +#define KEYWORD_SCAN_X1 0xd2 +#define KEYWORD_SCAN_X2 0xd3 +#define KEYWORD_SCAN_X3 0xd4 +#define KEYWORD_SCAN_X4 0xd5 +#define KEYWORD_SCAN_Y1 0xd6 +#define KEYWORD_SCAN_Y2 0xd7 +#define KEYWORD_SCAN_Y3 0xd8 +#define KEYWORD_SCAN_Y4 0xd9 +#define KEYWORD_THEN 0xf0 +#define KEYWORD_CHR 0xf1 +#define KEYWORD_TO 0xf2 +#define KEYWORD_STEP 0xf3 + +#define KEYWORDS_STATEMENT_FROM 0x80 +#define KEYWORDS_STATEMENT_TO 0x97 +#define KEYWORDS_2OP_FROM 0xa0 +#define KEYWORDS_2OP_TO 0xa2 + + +/* end of keywords.h */ diff --git a/makefile b/makefile new file mode 100644 index 0000000..d126588 --- /dev/null +++ b/makefile @@ -0,0 +1,23 @@ + +# start up routine +C0WW_JAPANESE2=..\common\c0wwjpn2.obj + +C0WW=$(C0WW_JAPANESE2) + +LIBWW=@..\common\libww.rsp + +CFLAGS=-DWW -ms -zPCGROUP -zSDGROUP -zGDGROUP + +all: wonbe.fx + +wonbe.fx: wonbe.bin + mkfent wonbe.cf + +wonbe.bin: wonbe.obj + tlink /m /c $(C0WW) wonbe, wonbe, wonbe, $(LIBWW) + exe2fbin wonbe.exe wonbe.bin + +wonbe.obj: wonbe.c + tcc -c $(CFLAGS) $(DEFINES) -IC:\vshare\ww\dev\WWitch\include wonbe.c + + diff --git a/test.wb b/test.wb new file mode 100644 index 0000000..5ec1b92 --- /dev/null +++ b/test.wb @@ -0,0 +1,2 @@ +10 print 1 +20 print 2 diff --git a/testcont.wb b/testcont.wb new file mode 100644 index 0000000..a00a260 --- /dev/null +++ b/testcont.wb @@ -0,0 +1,3 @@ +100 debug "contしてね" +200 break +300 debug "contされたよ" diff --git a/testfor.wb b/testfor.wb new file mode 100644 index 0000000..4a7dd58 --- /dev/null +++ b/testfor.wb @@ -0,0 +1,11 @@ +100 rem ワンべぇ テストプログラム +200 rem forのテストその1 +210 print "loop by global=":for I=0 to 9:print I,:next:print +215 print "PUSH ANY BUTTON";wait +220 print "loop by local=":for i=0 to 9:print i,:next:print +225 print "PUSH ANY BUTTON";wait +230 print "loop by array=":for @(0)=0 to 9:print @(0),:next:print +235 print "PUSH ANY BUTTON";wait +240 print "step 2=":for i=0 to 18 step 2:print i,:next:print +245 print "PUSH ANY BUTTON";wait +250 print "step -1=":for i=9 to 0 step -1:print i,:next:print diff --git a/testgosub.wb b/testgosub.wb new file mode 100644 index 0000000..dfb09b8 --- /dev/null +++ b/testgosub.wb @@ -0,0 +1,19 @@ +100 'gosubとローカル変数のテスト +200 a=1 +210 gosub 1000 +220 if a <> 1 then print "220でエラー" +300 print "main return" +900 end +1000 'sub1 +1010 print "sub1" +1100 a=123 +1200 if a <> 123 then print "1200でエラー" +1300 gosub 2000 +1400 if a <> 123 then print "1400でエラー" +1450 print "sub1 return" +1500 return +2000 'sub2 +2010 print "sub2" +2100 a=321 +2200 if a <> 321 then print "2200でエラー" +2500 return diff --git a/testif.wb b/testif.wb new file mode 100644 index 0000000..b16b6b4 --- /dev/null +++ b/testif.wb @@ -0,0 +1,9 @@ +10 if 1 then print "条件成立" +20 if 0 then print "条件不成立" +30 if 1 then if 1 then if 1 then print "多重条件成立" +40 print "ifによるループ" +50 i = 0 +60 print i;" "; +70 i=i+1 +80 if i < 10 then goto 60 +90 print "終了",wait diff --git a/testlocate.wb b/testlocate.wb new file mode 100644 index 0000000..2aeb20b --- /dev/null +++ b/testlocate.wb @@ -0,0 +1,7 @@ +2 rem cls, localeのテスト +5 cls +7 randomize tick +10 for i=0 to 999 +20 locate rnd(28),rnd(18) +30 print chr(rnd(26)+0x41); +40 next diff --git a/testlongloop.wb b/testlongloop.wb new file mode 100644 index 0000000..7848231 --- /dev/null +++ b/testlongloop.wb @@ -0,0 +1 @@ +10 for i=0 to 32767:print "test";i:next diff --git a/win32text.c b/win32text.c new file mode 100644 index 0000000..67dee98 --- /dev/null +++ b/win32text.c @@ -0,0 +1,275 @@ +// wonbe Win32 text emulation +// First Created: Nov.4,2000 by Nashiko +// Copyright 2000 (c) by Pie Dey Co.,Ltd. + +#include +#include "win32text.h" + +#define SCREEN_SIZE_X (224/8) +#define SCREEN_SIZE_Y (144/8) +static WORD screen[SCREEN_SIZE_X][SCREEN_SIZE_Y]; + +static WORD lastChar; + +static HWND hwnd; + +static void wmPaint( HWND hWnd, HDC hdc ) +{ + int x,y; + int xArea, yArea; + RECT rect, rectDraw; + TEXTMETRIC tm; + + GetClientRect( hWnd, &rect ); + + GetTextMetrics( hdc, &tm ); + + xArea = SCREEN_SIZE_X * tm.tmMaxCharWidth; + yArea = SCREEN_SIZE_Y * tm.tmHeight; + + rectDraw.left = (rect.right-rect.left)/2-xArea/2; + rectDraw.top = (rect.bottom-rect.top)/2-yArea/2; + rectDraw.right = (rect.right-rect.left)/2+xArea/2; + rectDraw.bottom = (rect.bottom-rect.top)/2+yArea/2; + + FillRect( hdc, &rect, GetStockObject(GRAY_BRUSH) ); + FillRect( hdc, &rectDraw, GetStockObject(WHITE_BRUSH) ); + + for( y=0; y= 0x100 ) { + str[0] = (val >> 8); + str[1] = (val & 0xff); + TextOut( hdc, + rectDraw.left+x*tm.tmMaxCharWidth, + rectDraw.top+y*tm.tmHeight, + str, 2 ); + } else { + str[0] = (BYTE)val; + TextOut( hdc, + rectDraw.left+x*tm.tmMaxCharWidth, + rectDraw.top+y*tm.tmHeight, + str, 1 ); + } + } + } +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC hdc; + + switch (message) { + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + wmPaint(hWnd,hdc); + EndPaint(hWnd, &ps); + break; + + case WM_CHAR: + lastChar = (WORD)wParam; + break; + + case WM_CLOSE: + return 0; // 閉じちゃ駄目 + + case WM_DESTROY: + hwnd = NULL; + PostQuitMessage(0); + break; + + default: + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + return (0); +} + +static int createTextInThread() +{ + WNDCLASS wc; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandle(NULL); + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = "wonbe_win32text"; + RegisterClass(&wc); + + hwnd = CreateWindow(wc.lpszClassName, "WONBE TEXT", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, SCREEN_SIZE_X*16+64, SCREEN_SIZE_Y*20+64, + NULL, NULL, wc.hInstance, NULL); + + if( !hwnd ) return FALSE; + + clearText(); + ShowWindow( hwnd, SW_SHOW ); + UpdateWindow( hwnd ); + + return TRUE; +} + +void clearText() +{ + int x,y; + if( hwnd == NULL ) return; + for( y=0; y= SCREEN_SIZE_X ) return; + if( y >= SCREEN_SIZE_Y ) return; + screen[x][y] = ch; + InvalidateRect( hwnd, NULL, FALSE ); +} + +void updateText() +{ + UpdateWindow( hwnd ); +} + +void deleteText() +{ + if( hwnd == NULL ) return; + DestroyWindow( hwnd ); + hwnd = NULL; +} + +DWORD WINAPI ThreadFunc( LPVOID lpParam ) +{ + MSG msg; + createTextInThread(); + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +int createText() +{ + DWORD dwThreadId, dwThrdParam = 1; + HANDLE hThread; + + lastChar = 0; + hThread = CreateThread( + NULL, // no security attributes + 0, // use default stack size + ThreadFunc, // thread function + &dwThrdParam, // argument to thread function + 0, // use default creation flags + &dwThreadId); // returns the thread identifier + return TRUE; +} + +unsigned short win32_wait() +{ + WORD t; + while( TRUE ) { + // 以下の2行は本当はマルチスレッド的にNGなんだけど + // テスト用環境だから大目に見る + t = lastChar; + lastChar = 0; + switch( t ) { + case 'p': + case 'P': + return 0x02; // START BUTTON + case ' ': + return 0x04; //KEYWORD_SCAN_A; + case 0x1b: + return 0x08; //KEYWORD_SCAN_B; + case 'e': + case 'E': + return 0x10; //KEYWORD_SCAN_X1; + case 'd': + case 'D': + return 0x20; //KEYWORD_SCAN_X2; + case 'x': + case 'X': + return 0x40; //KEYWORD_SCAN_X3; + case 's': + case 'S': + return 0x80; //KEYWORD_SCAN_X4; + case 't': + case 'T': + return 0x100; //KEYWORD_SCAN_Y1; + case 'g': + case 'G': + return 0x200; //KEYWORD_SCAN_Y2; + case 'v': + case 'V': + return 0x400; //KEYWORD_SCAN_Y3; + case 'f': + case 'F': + return 0x800; //KEYWORD_SCAN_Y4; + } + Sleep( 100 ); + } +} + +unsigned short win32_scan() +{ + WORD t; + t = 0; + if( GetAsyncKeyState('P') & 0x8000 ) { + t |= 0x02; // START + } + if( GetAsyncKeyState(VK_SPACE) & 0x8000 ) { + t |= 0x04; // A + } + if( GetAsyncKeyState(VK_ESCAPE) & 0x8000 ) { + t |= 0x08; // B + } + if( GetAsyncKeyState('E') & 0x8000 ) { + t |= 0x10; // X1 + } + if( GetAsyncKeyState('D') & 0x8000 ) { + t |= 0x20; // X2 + } + if( GetAsyncKeyState('X') & 0x8000 ) { + t |= 0x40; // X3 + } + if( GetAsyncKeyState('S') & 0x8000 ) { + t |= 0x80; // X4 + } + if( GetAsyncKeyState('T') & 0x8000 ) { + t |= 0x100; // Y1 + } + if( GetAsyncKeyState('G') & 0x8000 ) { + t |= 0x200; // Y2 + } + if( GetAsyncKeyState('V') & 0x8000 ) { + t |= 0x400; // Y3 + } + if( GetAsyncKeyState('F') & 0x8000 ) { + t |= 0x800; // Y4 + } + return t; +} + +unsigned int win32_get_tick_count() +{ + return GetTickCount()/10; +} + +void win32_sys_wait( unsigned int val ) +{ + Sleep( val*10 ); +} + +// end of win32text.c diff --git a/win32text.h b/win32text.h new file mode 100644 index 0000000..a781c2f --- /dev/null +++ b/win32text.h @@ -0,0 +1,15 @@ +// wonbe Win32 text emulation +// First Created: Nov.4,2000 by Nashiko +// Copyright 2000 (c) by Pie Dey Co.,Ltd. + +int createText(); +void clearText(); +void drawChar( int x, int y, unsigned short ch ); +void updateText(); +void deleteText(); +unsigned short win32_wait(); +unsigned short win32_scan(); +unsigned int win32_get_tick_count(); +void win32_sys_wait( unsigned int val ); + +// end of win32text.h diff --git a/wonbe.c b/wonbe.c new file mode 100644 index 0000000..abcc174 --- /dev/null +++ b/wonbe.c @@ -0,0 +1,1974 @@ +/* wonbe: WonderWitch Basic Environment */ +/* First Created: Nov.3,2000 by Nashiko */ +/* Copyright 2000 (c) by Pie Dey Co.,Ltd. */ + +/* This source code is for both VC++6.0 and Turbo C 2.0 */ + +#include +#include +#include +#ifdef WW +#include +#include +#include +#include +#endif +#include "keywords.h" +#ifdef WIN32 +#include "win32text.h" +#endif + +char myVersion[] = "0.01"; + +#ifdef WW +#define MEMMOVE mymemmove +#define FAR far +#else +#define MEMMOVE mymemmove +#define FAR +#endif + +#ifdef WIN32 +typedef unsigned char BYTE; +#endif +typedef unsigned short WORD; +typedef signed short SHORT; + +#define EOL (0x0d) + +#ifdef WIN32 +typedef int BOOL; +#endif +#define FALSE 0 +#define TRUE 1 + +typedef void (*NEARPROC)(); + +#define WORKAREA_SIZE ((WORD)49152) +#define LINE_SIZE (256) + +/* 実行のみのモードで動いているとき (シリアル経由で端末が居ないとき) */ +BOOL runtimeOnly; + +#ifdef WW +void fatalExit( const char * msg ) +{ + text_screen_init(); + text_put_string( 0, 0, (char*)msg ); + text_put_string( 0, 3, "PUSH ANY BUTTON" ); + key_wait(); +} +#endif + +BOOL commonPrint( FILE FAR * fp, const char * msg,... ) +{ +#ifdef WW + static +#endif + char buf[256]; + vsprintf(buf, msg, (va_list)(&msg+1) ); + if( fp != NULL ) { + int r; + r = fprintf( fp, buf ); + return r >= 0; + } else { +#ifdef WW + if( runtimeOnly ) { + fatalExit( buf ); + } else { + comm_send_string( buf ); + } +#else + printf( buf ); +#endif + } + return TRUE; +} + +void consoleInput( BYTE * buf, WORD len ) +{ +#ifdef WW + WORD cursor; + if( runtimeOnly ) { + fatalExit("consoleInput not allowed in runtime mode"); + } else { + cursor = 0; + while( TRUE ) { + int ch; + ch = comm_receive_char(); + if( ch == 0x0d ) { /* CR */ + buf[cursor] = '\0'; + return; + } + if( ch == 0x09 ) { /* TAB */ + goto inputAsChar; + } + if( ch == 0x08 ) { /* BS */ + if( cursor > 0 ) { + cursor--; + comm_send_char( ch ); + continue; + } + } + if( ch >= 0 && ch < ' ' ) { + /* ignore it */ + continue; + } + if( ch >= ' ' && ch <= 0xfc ) { +inputAsChar: + if( cursor < len-1 ) { + buf[cursor] = ch; + cursor++; + comm_send_char( ch ); + } + } + } + } +#else + gets(buf); +#endif +} + +typedef struct { + WORD id; + const BYTE * name; +} KEYWORDITEM; + +KEYWORDITEM keywords[] = { + { KEYWORD_IF,"if" }, + { KEYWORD_PRINT,"print" }, + { KEYWORD_LOCATE,"locate" }, + { KEYWORD_CLS,"cls" }, + { KEYWORD_GOTO,"goto" }, + { KEYWORD_GOSUB,"gosub" }, + { KEYWORD_RETURN,"return" }, + { KEYWORD_FOR,"for" }, + { KEYWORD_NEXT,"next" }, + { KEYWORD_END,"end" }, + { KEYWORD_BREAK,"break" }, + { KEYWORD_REM,"rem" }, + { KEYWORD_NEW,"new" }, + { KEYWORD_LIST,"list" }, + { KEYWORD_RUN,"run" }, + { KEYWORD_CONT,"cont" }, + { KEYWORD_SAVE,"save" }, + { KEYWORD_LOAD,"load" }, + { KEYWORD_MERGE,"merge" }, + { KEYWORD_RANDOMIZE,"randomize" }, + { KEYWORD_EXIT,"exit" }, + { KEYWORD_DEBUG,"debug" }, + { KEYWORD_WAITVB,"waitvb" }, + { KEYWORD_FILES,"files" }, + { KEYWORD_AND,"and" }, + { KEYWORD_OR,"or" }, + { KEYWORD_XOR,"xor" }, + { KEYWORD_NOT,"not" }, + { KEYWORD_SCAN,"scan" }, + { KEYWORD_WAIT,"wait" }, + { KEYWORD_RND,"rnd" }, + { KEYWORD_ABS,"abs" }, + { KEYWORD_TICK,"tick" }, + { KEYWORD_SCAN_A,"scan_a" }, + { KEYWORD_SCAN_B,"scan_b" }, + { KEYWORD_SCAN_X1,"scan_x1" }, + { KEYWORD_SCAN_X2,"scan_x2" }, + { KEYWORD_SCAN_X3,"scan_x3" }, + { KEYWORD_SCAN_X4,"scan_x4" }, + { KEYWORD_SCAN_Y1,"scan_y1" }, + { KEYWORD_SCAN_Y2,"scan_y2" }, + { KEYWORD_SCAN_Y3,"scan_y3" }, + { KEYWORD_SCAN_Y4,"scan_y4" }, + { KEYWORD_THEN,"then" }, + { KEYWORD_CHR,"chr" }, + { KEYWORD_TO,"to" }, + { KEYWORD_STEP,"step" }, + { 0,NULL } +}; + +/* インタラクティブモード時の1行バッファ */ +BYTE waRawLine[LINE_SIZE]; +BYTE waCoockedLine[LINE_SIZE]; + +/* コードとデータを収める領域 */ +WORD codeTop; +WORD dataTop; +/*WORD savedPointer; /* breakしたときの実行中位置 */ +BYTE wa[WORKAREA_SIZE]; + +/* グローバル変数領域 */ +#define NUMBER_OF_SIMPLE_VARIABLES (26) +SHORT globalVariables[NUMBER_OF_SIMPLE_VARIABLES]; +SHORT topLevelVariables[NUMBER_OF_SIMPLE_VARIABLES]; +SHORT * localVariables; /* あるスコープで有効なローカル変数領域を持つ */ + +/* 現在実行中の位置に関する情報 */ +/* waかwaCookedLineのどちらかの中を示すかNULL */ +BYTE * executionPointer; +/* contコマンドで実行を再開するポイント */ +BYTE * resumePointer; + +/* 現在処理中の行番号 (0ならダイレクトモード) */ +WORD currentLineNumber; + +/* gosubとforのためのスタック */ +#define STACK_TYPE_GOSUB 1 +#define STACK_TYPE_FOR 2 +typedef struct { + WORD type; /* 1==GOSUB, 2==FOR */ + /* for GOSUB and FOR */ + BYTE * returnPointer; + /* for GOSUB */ + SHORT * lastLocalVariables; + SHORT simpleVariables[NUMBER_OF_SIMPLE_VARIABLES]; + /* for FOR */ + SHORT * pvar; /* counter variable */ + SHORT limit; /* limit value */ + SHORT step; /* step value */ +} STACK; +#define STACK_MAX 8 +STACK stacks[STACK_MAX]; +int stackPointer; + +/* インタラクティブモードかインタプリタモードか */ +BOOL bInteractive; + +/* インタプリタ脱出後の振る舞いのリクエスト */ +BOOL bForceToReturnSuper; + +int requestNextAction; /* 以下のいずれか */ +/* 何もせず現状のまま */ +#define REQUEST_NO_ACTION 0 +/* 対話モードへ行け */ +#define REQUEST_INTERACTIVE 1 +/* runLineNumberから実行を開始せよ */ +#define REQUEST_RUN_LINENUMBER 2 +/* waRawLineに入っている文字列をファイル名としてそれを読み込んで実行せよ */ +#define REQUEST_RUN_FILE 3 +/* newせよ */ +#define REQUEST_NEW 4 +/* waRawLineに入っている文字列をファイル名としてそれをロード */ +#define REQUEST_LOAD_FILE 5 +/* WONBEを終了してOSに戻れ */ +#define REQUEST_EXIT_SYSTEM 6 +/* waRawLineに入っている文字列をファイル名としてそれをマージ */ +#define REQUEST_MERGE_FILE 7 +/* REQUEST_RUN_LINENUMBERで実行開始をリクエストする行番号 */ +WORD runLineNumber; + +/* エラー発生 */ +void syntaxError() +{ + commonPrint(NULL, "Syntax Error in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void divideByZero() +{ + commonPrint(NULL, "Divide by 0 in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void outOfArraySubscription() +{ + commonPrint(NULL, "Out of Array Subscription in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void lineNumberNotFound( WORD lineNumber ) +{ + commonPrint(NULL, "Line Number %d not Found in %d\x07\n", lineNumber, currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void stackOverflow() +{ + commonPrint(NULL, "Stack Overflow in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void stackUnderflow() +{ + commonPrint(NULL, "Stack Underflow in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void nextWithoutFor() +{ + commonPrint(NULL, "Next without For in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void outOfMemory() +{ + commonPrint(NULL, "Out of memory in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void loadError() +{ + commonPrint(NULL, "File Not Found or Load Error in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void cantContinue() +{ + commonPrint(NULL, "Can't Continue in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void saveError() +{ + commonPrint(NULL, "Save Erroor in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +void paramError() +{ + commonPrint(NULL, "Parameter Erroor in %d\x07\n", currentLineNumber ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +/* ユーティリティ関数達 */ +void mymemmove( BYTE * dst, const BYTE * src, WORD len ) +{ + WORD i; + if( dst < src ) { + for( i=0; i= 'A' && ch <= 'Z' ) { + return ch - 'A' + 'a'; + } + return ch; +} + +/* シフトJISの1バイト目かどうか判断。マクロなので副作用に注意 */ +#define IsDBCSLeadByte(ch) ((ch >= 0x81 && ch <= 0x9f) || (ch >= 0xe0 && ch <= 0xfc)) + +/* 実行時情報のクリア (contできなくなる) */ +void clearRuntimeInfo() +{ + memset( globalVariables, 0, sizeof(globalVariables) ); + memset( topLevelVariables, 0, sizeof(topLevelVariables) ); + memset( stacks, 0, sizeof(globalVariables) ); + executionPointer = NULL; + resumePointer = NULL; + currentLineNumber = 0; + localVariables = topLevelVariables; + stackPointer = 0; + srand(0); +} + +/* 行頭の行番号の、実行時の定型処理 */ +void processLineHeader() +{ + if( !bInteractive ) { + currentLineNumber = *((WORD *)executionPointer); + executionPointer += 2; + } else { + currentLineNumber = 0; + } +} + +/* 行番号処理 */ +BYTE * getLineReferenceFromLineNumber( WORD lineNumber ) +{ + BYTE * p; + WORD t; + p = wa; + while( TRUE ) { + t = *((WORD *)p); + if( t == 0 ) { + return NULL; + } + if( lineNumber == t ) { + return p; + } + p += 2; + p = skipToEOL( p ); + p++; + } +} + +BYTE * getInsertionPointFromLineNumber( WORD lineNumber ) +{ + BYTE * p; + WORD t; + p = wa; + while( TRUE ) { + t = *((WORD *)p); + if( t == 0 ) { + return p; + } + if( lineNumber <= t ) { + return p; + } + p += 2; + p = skipToEOL( p ); + p++; + } +} + +/* 配列管理 */ +int availableArrayItems() +{ + return (WORKAREA_SIZE-dataTop) >> 1; +} + +SHORT * derefArrayItem( int index ) +{ + if( index < 0 || index >= availableArrayItems() ) { + outOfArraySubscription(); + return NULL; /* そのインデックスは使えません */ + } + return (SHORT*)(&wa[dataTop+index*2]); +} + +/* 物理テキストの管理 */ +#define SCREEN_SIZE_X (224/8) +#define SCREEN_SIZE_Y (144/8) + +WORD screen[SCREEN_SIZE_X][SCREEN_SIZE_Y]; + +SHORT xCursor, yCursor; + +#define TABSTOP 8 + +void ptextScrollUp() +{ + int x, y; + for( y=0; y= SCREEN_SIZE_Y ) { + ptextScrollUp(); + yCursor = SCREEN_SIZE_Y-1; + } +} + +void ptextTab() +{ + if( xCursor+TABSTOP >= SCREEN_SIZE_X ) { + ptextNewline(); + return; + } + xCursor = (xCursor+TABSTOP) / TABSTOP * TABSTOP; +} + +void ptextString( const BYTE * msg ) +{ + while( TRUE ) { + WORD ch; + if( *msg == '\0' ) break; + if( IsDBCSLeadByte(*msg) ) { + ch = (msg[0] << 8) + msg[1]; + msg+=2; + } else { + ch = msg[0]; + msg++; + } + screen[xCursor][yCursor] = ch; +#ifdef WIN32 + drawChar( xCursor, yCursor, ch ); +#endif +#ifdef WW + text_put_char( xCursor, yCursor, ch ); +#endif + xCursor++; + if( xCursor >= SCREEN_SIZE_X ) { + xCursor = 0; + yCursor++; + if( yCursor >= SCREEN_SIZE_Y ) { + ptextScrollUp(); + yCursor = SCREEN_SIZE_Y-1; + } + } + } +} + +void ptextLocate( int x, int y ) +{ + if( x < 0 ) x = 0; + if( x >= SCREEN_SIZE_X ) x = SCREEN_SIZE_X-1; + if( y < 0 ) y = 0; + if( y >= SCREEN_SIZE_Y ) y = SCREEN_SIZE_Y-1; + xCursor = x; + yCursor = y; +} + +void ptextCLS() +{ + int x,y; + xCursor = 0; + yCursor = 0; +#ifdef WIN32 + clearText(); +#endif +#ifdef WW + for( y=0; y to ) break; + p += 2; + b = commonPrint(fp,"%d",lineNumber); + if( b == FALSE ) return FALSE; + while( TRUE ) { + if( *p == EOL ) { + p++; + break; + } + if( *p == 0x01 ) { + WORD n; + p++; + n = *((WORD*)p); + p += 2; + b = commonPrint(fp,"%d",n); + if( b == FALSE ) return FALSE; + } else if( *p == 0x02 ) { + WORD n; + p++; + n = *((WORD*)p); + p += 2; + b = commonPrint(fp,"0x%x",n); + if( b == FALSE ) return FALSE; + } else if( *p == 0x03 ) { + p++; + b = commonPrint(fp,"\"%s\"",p); + if( b == FALSE ) return FALSE; + p += strlen(p)+1; + } else if( *p == '\'' ) { /* コメントのあとはそのまま行末まで転送 */ + while( TRUE ) { + if( *p == EOL ) break; + b = commonPrint(fp,"%c",*p); + if( b == FALSE ) return FALSE; + p++; + } + } else if( *p >= 0x80 ) { + KEYWORDITEM * k = keywords; + while( TRUE ) { + if( k->id == 0 ) { + b = commonPrint(fp,"[?%x?]", *p ); + if( b == FALSE ) return FALSE; + p++; + break; + } + if( k->id == *p ) { + b = commonPrint(fp, k->name ); + if( b == FALSE ) return FALSE; + p++; + if( k->id == KEYWORD_REM ) { /* コメントのあとはそのまま行末まで転送 */ + while( TRUE ) { + if( *p == EOL ) break; + b = commonPrint(fp,"%c",*p); + if( b == FALSE ) return FALSE; + p++; + } + } + break; + } + k++; + } + } else { + b = commonPrint(fp,"%c",*p); + if( b == FALSE ) return FALSE; + p++; + } + } + b = commonPrint(fp,"\n"); + if( b == FALSE ) return FALSE; + } + return TRUE; +} + +/* 式計算機能 */ +SHORT expr(); /* forward decl */ + +SHORT * getArrayReference() +{ + BYTE ch; + int index; + SHORT * pvar; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != '(' && ch != '[' ) { + syntaxError(); + return NULL; + } + index = expr(); + if( bForceToReturnSuper ) return NULL; + pvar = derefArrayItem( index ); + if( pvar == NULL ) return NULL; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != ')' && ch != ']' ) { + syntaxError(); + return NULL; + } + return pvar; +} + +SHORT calcValue() +{ + BYTE ch; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch >= 'A' && ch <= 'Z' ) { + return globalVariables[ch-'A']; + } + if( ch >= 'a' && ch <= 'z' ) { + return localVariables[ch-'a']; + } + if( ch == '@' ) { + SHORT * pvar; + pvar = getArrayReference(); + if( pvar == NULL ) return -1; + return *pvar; + } + switch( ch ) { + case 0x01: /* 次にあるのは10進2バイト整数 */ + case 0x02: /* 次にあるのは16進2バイト整数 */ + { + SHORT t; + t = *((SHORT *)executionPointer); + executionPointer += 2; + return t; + } + case '(': + { + SHORT t; + t = expr(); + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != ')' ) { + syntaxError(); + return -1; + } + return t; + } + case '-': + return -calcValue(); + case KEYWORD_NOT: + return ~calcValue(); + case KEYWORD_SCAN: +#ifdef WW + return key_press_check(); +#else + return win32_scan(); +#endif + case KEYWORD_WAIT: +#ifdef WW + return key_wait(); +#else + return win32_wait(); +#endif + case KEYWORD_RND: + { + SHORT t; + t = calcValue(); + return rand() % t; + } + case KEYWORD_ABS: + { + SHORT t; + t = calcValue(); + if( t < 0 ) return -t; + return t; + } + case KEYWORD_TICK: +#ifdef WW + return sys_get_tick_count(); +#else + return win32_get_tick_count(); +#endif + case KEYWORD_SCAN_A: + return 4; + case KEYWORD_SCAN_B: + return 8; + case KEYWORD_SCAN_X1: + return 16; + case KEYWORD_SCAN_X2: + return 32; + case KEYWORD_SCAN_X3: + return 64; + case KEYWORD_SCAN_X4: + return 128; + case KEYWORD_SCAN_Y1: + return 256; + case KEYWORD_SCAN_Y2: + return 512; + case KEYWORD_SCAN_Y3: + return 1024; + case KEYWORD_SCAN_Y4: + return 2048; + } + syntaxError(); + return -1; +} + +SHORT expr() +{ + SHORT acc; + acc = calcValue(); + if( bForceToReturnSuper ) return -1; + + while( TRUE ) { + BYTE ch; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + switch( ch ) { + case '+': + acc = acc + calcValue(); + break; + case '-': + acc = acc - calcValue(); + break; + case '*': + acc = acc * calcValue(); + break; + case '/': + { + SHORT t; + t = calcValue(); + if( t == 0 ) { + divideByZero(); + } else { + acc = acc / t; + } + } + break; + case KEYWORD_AND: + acc = acc & calcValue(); + break; + case KEYWORD_OR: + acc = acc | calcValue(); + break; + case KEYWORD_XOR: + acc = acc ^ calcValue(); + break; + case '>': + { + BYTE ch2; + while( TRUE ) { + ch2 = *executionPointer++; + if( ch2 != ' ' && ch2 != '\t' ) break; + } + if( ch2 == '=' ) { + acc = (acc >= calcValue()); + } else { + executionPointer--; + acc = (acc > calcValue()); + } + } + break; + case '<': + { + BYTE ch2; + while( TRUE ) { + ch2 = *executionPointer++; + if( ch2 != ' ' && ch2 != '\t' ) break; + } + if( ch2 == '=' ) { + acc = (acc <= calcValue()); + } else if( ch2 == '>' ) { + acc = (acc != calcValue()); + } else { + executionPointer--; + acc = (acc < calcValue()); + } + } + break; + case '=': + acc = (acc == calcValue()); + break; + default: + executionPointer--; /* unget it */ + return acc; + } + if( bForceToReturnSuper ) return -1; + } +} + +/* 各ステートメント実行処理メイン */ + +void st_assignment( SHORT * pvar ) /* 代入ステートメントだけ例外的に処理する */ +{ + BYTE ch; + SHORT val; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != '=' ) { + syntaxError(); + return; + } + val = expr(); + if( bForceToReturnSuper ) return; + *pvar = val; +} + +void st_if() +{ + SHORT val; + BYTE ch; + val = expr(); + if( bForceToReturnSuper ) return; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != KEYWORD_THEN ) { + syntaxError(); + return; + } + if( val != 0 ) { + return; /* thenの次から継続実行する */ + } + /* 条件不成立につき、行末まで読み飛ばす */ + executionPointer = skipToEOL( executionPointer ); +} + +void printOrDebug( BOOL bPrint ) +{ + WORD lastChar; + BYTE ch; + lastChar = '\0'; + while( TRUE ) { + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == EOL || ch == ':' || ch == '\'' ) { + executionPointer--; /* unget it */ + break; + } + lastChar = ch; + switch( ch ) { + case 0x03: + if( bPrint ) { + ptextString( executionPointer ); + } else { + commonPrint( NULL, executionPointer ); + } + while( TRUE ) { + ch = *executionPointer++; + if( ch == '\0' ) break; + } + break; + case ';': + break; + case ',': + if( bPrint ) { + ptextTab(); + } else { + commonPrint( NULL, "\t" ); + } + break; + case KEYWORD_CHR: + { + WORD val; +#ifdef WW + static +#endif + BYTE str[3]; + val = expr(); + if( bForceToReturnSuper ) return; + if( val >= 0x100 ) { + str[0] = (val >> 8); + str[1] = (val & 0xff); + str[2] = '\0'; + } else { + str[0] = (BYTE)val; + str[1] = '\0'; + } + if( bPrint ) { + ptextString( str ); + } else { + commonPrint( NULL, str ); + } + } + break; + default: + { + WORD val; +#ifdef WW + static +#endif + BYTE str[10]; + executionPointer--; /* unget it */ + val = expr(); + if( bForceToReturnSuper ) return; + sprintf( str, "%d", val ); + if( bPrint ) { + ptextString( str ); + } else { + commonPrint( NULL, str ); + } + } + break; + } + } + if( lastChar != ';' && lastChar != ',' ) { + if( bPrint ) { + ptextNewline(); + } else { + commonPrint( NULL, "\r\n" ); + } + } +} + +void st_print() +{ + printOrDebug( TRUE ); +} + +void st_debug() +{ + printOrDebug( FALSE ); +} + +void st_locate() +{ + SHORT x, y; + BYTE ch; + x = expr(); + if( bForceToReturnSuper ) return; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != ',' ) { + syntaxError(); + return; + } + y = expr(); + if( bForceToReturnSuper ) return; + ptextLocate( x, y ); +} + +void st_cls() +{ + ptextCLS(); +} + +void st_goto() +{ + SHORT val; + BYTE * t; + val = expr(); + if( bForceToReturnSuper ) return; + t = getLineReferenceFromLineNumber( val ); + if( t == NULL ) { + lineNumberNotFound( val ); + return; + } + executionPointer = t; + bInteractive = FALSE; + processLineHeader(); +} + +void st_gosub() +{ + SHORT val; + BYTE * t; + val = expr(); + if( bForceToReturnSuper ) return; + t = getLineReferenceFromLineNumber( val ); + if( t == NULL ) { + lineNumberNotFound( val ); + return; + } + if( stackPointer+1 >= STACK_MAX ) { + stackOverflow(); + return; + } + stacks[stackPointer].type = STACK_TYPE_GOSUB; + stacks[stackPointer].returnPointer = executionPointer; + stacks[stackPointer].lastLocalVariables = localVariables; + localVariables = stacks[stackPointer].simpleVariables; + stackPointer++; + executionPointer = t; + bInteractive = FALSE; + processLineHeader(); +} + +void st_return() +{ + while( TRUE ) { + if( stackPointer == 0 ) { + stackUnderflow(); + return; + } + stackPointer--; + if( stacks[stackPointer].type == STACK_TYPE_GOSUB ) break; + } + executionPointer = stacks[stackPointer].returnPointer; + if( executionPointer >= waCoockedLine && executionPointer < waCoockedLine+LINE_SIZE ) { + bInteractive = TRUE; + } + localVariables = stacks[stackPointer].lastLocalVariables; +} + +void st_for() +{ + BYTE ch; + SHORT from, to, step; + SHORT * pvar; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == '@' ) { /* is it l-value? */ + pvar = getArrayReference(); + if( pvar == NULL ) return; + } else if( ch >= 'A' && ch <= 'Z' ) { + pvar = &globalVariables[ch-'A']; + } else if( ch >= 'a' && ch <= 'z' ) { + pvar = &localVariables[ch-'a']; + } else { + syntaxError(); + return; + } + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != '=' ) { + syntaxError(); + return; + } + from = expr(); + if( bForceToReturnSuper ) return; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != KEYWORD_TO ) { + syntaxError(); + return; + } + to = expr(); + if( bForceToReturnSuper ) return; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == KEYWORD_STEP ) { + step = expr(); + if( bForceToReturnSuper ) return; + } else { + step = 1; + executionPointer--; /* unget it */ + } + + if( stackPointer+1 >= STACK_MAX ) { + stackOverflow(); + return; + } + stacks[stackPointer].type = STACK_TYPE_FOR; + stacks[stackPointer].returnPointer = executionPointer; + *pvar = from; + stacks[stackPointer].pvar = pvar; + stacks[stackPointer].limit = to; + stacks[stackPointer].step = step; + stackPointer++; +} + +void st_next() +{ + if( stackPointer == 0 ) { + nextWithoutFor(); + return; + } + if( stacks[stackPointer-1].type != STACK_TYPE_FOR ) { + nextWithoutFor(); + return; + } + if( stacks[stackPointer-1].limit == *(stacks[stackPointer-1].pvar) ) { + /* loop done */ + stackPointer--; + return; + } + /* count step and loop again */ + *(stacks[stackPointer-1].pvar) += stacks[stackPointer-1].step; + executionPointer = stacks[stackPointer-1].returnPointer; +} + +/* endステートメント: 正常な終了 */ +void st_end() +{ + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; +} + +/* breakステートメント: デバッグ用の中断 */ +void st_break() +{ + commonPrint(NULL, "Break in %d\x07\n", currentLineNumber); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; + resumePointer = executionPointer; /* contする場所はbreakの次。breakのみの例外処理 */ +} + +void st_rem() +{ + executionPointer = skipToEOL( executionPointer ); +} + +void st_new() +{ + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_NEW; +} + +void st_list() +{ + WORD from, to; + BYTE ch; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == ':' || ch == EOL || ch == '\'' ) { + executionPointer--; /* unget */ + from = 1; + to = 32767; + } else { + if( ch == 0x01 ) { + from = *((WORD*)executionPointer); + executionPointer += 2; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + } else { + from = 1; + } + if( ch != '-' ) { + executionPointer--; /* unget */ + to = from; + } else { + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == 0x01 ) { + to = *((WORD*)executionPointer); + executionPointer += 2; + } else { + executionPointer--; /* unget */ + to = 32767; + } + } + } + sourceDump( NULL, from, to ); /* リスト出力の本体を呼ぶ */ +} + +void st_run() +{ + BYTE ch; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == ':' || ch == EOL || ch == '\'' ) { + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_RUN_LINENUMBER; + runLineNumber = 0; + } else if( ch == 0x03 ) { + strcpy( waRawLine, executionPointer ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_RUN_FILE; + } else { + SHORT val; + executionPointer--; /* unget it */ + val = expr(); + if( bForceToReturnSuper ) return; + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_RUN_LINENUMBER; + runLineNumber = val; + } +} + +void st_cont() +{ + if( resumePointer == NULL ) { + cantContinue(); + return; + } + executionPointer = resumePointer; + bInteractive = FALSE; +} + +void st_save() +{ + BYTE ch; + BOOL b; + FILE FAR * fp; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch != 0x03 ) { + syntaxError(); + return; + } + fp = fopen( executionPointer, "w" ); + if( fp == NULL ) { + saveError(); + return; + } + b = sourceDump( fp, 1, 32767 ); + fclose( fp ); + if( b == FALSE ) { + saveError(); + remove( executionPointer ); + return; + } + + executionPointer += strlen(executionPointer)+1; +} + +void st_load() +{ + BYTE ch; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == 0x03 ) { + strcpy( waRawLine, executionPointer ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_LOAD_FILE; + } else { + syntaxError(); + return; + } +} + +void st_merge() +{ + BYTE ch; + while( TRUE ) { + ch = *executionPointer++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == 0x03 ) { + strcpy( waRawLine, executionPointer ); + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_MERGE_FILE; + } else { + syntaxError(); + return; + } +} + +void st_randomize() +{ + SHORT val; + val = expr(); + srand( val ); +} + +void st_exit() +{ + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_EXIT_SYSTEM; +} + +void st_waitvb() +{ + SHORT val; + val = expr(); + if( bForceToReturnSuper ) return; + if( val < 0 || val > 750 ) { + paramError(); + return; + } +#ifdef WW + sys_wait( val ); +#endif +#ifdef WIN32 + win32_sys_wait( val ); +#endif +} + +void st_files() +{ +#ifdef WIN32 + commonPrint( NULL, "files statement not implemented in Win32\x07\n" ); +#endif +#ifdef WW + int i; + struct stat statbuf; + int nent; + + /*chdir("/rom0");*/ + nent = nument(NULL); + + for (i = 0; i < nent; i++) { + int result = getent(NULL, i, &statbuf); + if (result == E_FS_SUCCESS) { + if (statbuf.count != -1) { + /* Freya OSのバグ? 回避コード */ + int p, q; + p = 0; + q = 0; + waRawLine[p++] = '"'; + while( TRUE ) { + if( statbuf.name[q] == '\0' ) break; + waRawLine[p++] = statbuf.name[q++]; + } + waRawLine[p++] = '"'; + waRawLine[p++] = ','; + q = 0; + while( TRUE ) { + if( statbuf.info[q] == '\0' ) break; + waRawLine[p++] = statbuf.info[q++]; + } + waRawLine[p++] = '\0'; + commonPrint( NULL, "%s,%ld,%d\n", waRawLine, statbuf.len, statbuf.count ); + } + } else { + commonPrint( NULL, "*File Access Error\x07\n" ); + } + } +#endif +} + +/* 行エディタ */ +void editLine() +{ + WORD wishLineNumber; + BYTE ch, * p, * target; + /* トリックに注意! */ + /* 行頭の整数を、行番号に変換するには結果的に先頭の0x01を取り去るだけで良い */ + MEMMOVE( waCoockedLine, waCoockedLine+1, LINE_SIZE-1 ); + /* トリック終わり。この時点でwsCoockedLineは、プログラム内部表現の形式に一致している */ + wishLineNumber = *((WORD*)waCoockedLine); + p = waCoockedLine+2; + target = getLineReferenceFromLineNumber( wishLineNumber ); + while( TRUE ) { + ch = *p++; + if( ch != ' ' && ch != '\t' ) break; + } + if( ch == EOL ) { + WORD delta; + BYTE * from; + /* removing the line */ + if( target == NULL ) { + lineNumberNotFound( wishLineNumber ); + return; + } + from = skipToEOL(target)+1; + delta = from-target; + MEMMOVE( target, from, (WORD)(dataTop-(from-wa)) ); + dataTop -= delta; + clearRuntimeInfo(); + } else { + WORD len; + len = skipToEOL(waCoockedLine+2)-waCoockedLine+1; + if( target == NULL ) { + /* insert new line */ + /*const BYTE * to;*/ + if( dataTop + len >= WORKAREA_SIZE ) { + outOfMemory(); + return; + } + target = getInsertionPointFromLineNumber( wishLineNumber ); + /* to = skipToEOL(target)+1; */ + MEMMOVE( target+len, target, (WORD)(dataTop-(target-wa)) ); + MEMMOVE( target, waCoockedLine, len ); + dataTop += len; + clearRuntimeInfo(); + } else { + /* replace line */ + WORD lost; + BYTE * nextline; + int delta; + nextline = skipToEOL(target)+1; + lost = nextline-target; + delta = len-lost; + if( dataTop + delta >= WORKAREA_SIZE ) { + outOfMemory(); + return; + } + MEMMOVE( nextline+delta, nextline, (WORD)(dataTop-(nextline-wa)) ); + MEMMOVE( target, waCoockedLine, len ); + dataTop += delta; + clearRuntimeInfo(); + } + } +} + +/* 中間言語に翻訳する */ +BOOL convertInternalCode( BYTE * waCoockedLine, const BYTE * waRawLine ) +{ + const BYTE * src = waRawLine; + BYTE * dst = waCoockedLine; + while( TRUE ) { + if( *src == '\0' ) break; + if( *src == ' ' || *src == '\t' ) { + *dst++ = *src++; + } else if( *src < 0x20 ) { + syntaxError(); + return FALSE; + } else if( *src >= '0' && *src <= '9' ) { + if( *src == '0' && *(src+1) == 'x' ) { + WORD acc; + /* 16進のとき */ + *dst++ = 0x02; + acc = 0; + src += 2; + while( TRUE ) { + if( *src >= '0' && *src <= '9' ) { + acc *= 16; + acc += *src - '0'; + } else if( *src >= 'a' && *src <= 'f' ) { + acc *= 16; + acc += *src - 'a' + 10; + } else if( *src >= 'A' && *src <= 'F' ) { + acc *= 16; + acc += *src - 'A' + 10; + } else { + break; + } + src++; + } + *((WORD*)dst) = acc; + dst += 2; + } else { + SHORT acc; + /* 10進のとき */ + *dst++ = 0x01; + acc = *src-'0'; + src++; + while( TRUE ) { + if( *src < '0' || *src > '9' ) break; + acc *= 10; + acc += *src - '0'; + src++; + } + if( acc < 0 ) { /* overflow case */ + syntaxError(); + return FALSE; + } + *((SHORT*)dst) = acc; + dst += 2; + } + } else if( (*src >= 'a' && *src <= 'z') || (*src >= 'A' && *src <= 'Z') ) { + BYTE next = *(src+1); + if( (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') ) { + WORD id; + KEYWORDITEM * p = keywords; + id = 0; + while( TRUE ) { + const BYTE * ps, * pd; + if( p->id == 0 ) { + syntaxError(); + return FALSE; + } + ps = src; + pd = p->name; + while( TRUE ) { + if( *pd == '\0' ) { + id = p->id; + src = ps; + break; + } + if( mytolower(*ps) != mytolower(*pd) ) break; + ps++; + pd++; + } + if( id != 0 ) break; + p++; + } + *dst++ = (BYTE)id; + if( id == KEYWORD_REM ) { + /* コメント文の場合は行末まで何もかもそのままコピーする */ + while( TRUE ) { + if( *src == '\0' ) break; + *dst++ = *src++; + } + } + } else { + *dst++ = *src++; + } + } else if( *src == '\'' ) { + *dst++ = *src++; + /* コメント文の場合は行末まで何もかもそのままコピーする */ + while( TRUE ) { + if( *src == '\0' ) break; + *dst++ = *src++; + } + } else if( *src == '"' ) { + src++; + *dst++ = 0x03; + while( TRUE ) { + if( *src == '\0' ) { + syntaxError(); + return FALSE; + } + if( *src == '"' ) break; + *dst++ = *src++; + } + *dst++ = '\0'; + src++; + } else { + *dst++ = *src++; + } + } + *dst = EOL; + return TRUE; +} + +/* ステートメント実行処理関数のリスト */ + +NEARPROC statements[KEYWORDS_STATEMENT_TO-KEYWORDS_STATEMENT_FROM+1] = { + st_if, + st_print, + st_locate, + st_cls, + st_goto, + st_gosub, + st_return, + st_for, + st_next, + st_end, + st_break, + st_rem, + st_new, + st_list, + st_run, + st_cont, + st_save, + st_load, + st_merge, + st_randomize, + st_exit, + st_debug, + st_waitvb, + st_files +}; + +void interpreterMain() +{ + WORD keyscan; + while( TRUE ) { + /* 行の開始 */ + processLineHeader(); + /* 最後に達してしまった? */ + if( !bInteractive && currentLineNumber == 0 ) { + bForceToReturnSuper = TRUE; + requestNextAction = REQUEST_INTERACTIVE; + return; + } + + while( TRUE ) { + BYTE ch; + if( !bInteractive ) { + resumePointer = executionPointer; /* contする場所を記憶する */ + } + +#ifdef WW + keyscan = key_press_check(); +#else + keyscan = win32_scan(); +#endif + if( keyscan & 0x02 ) { + st_break(); + return; + } + + ch = *executionPointer++; + if( ch == EOL ) break; + if( ch == ' ' || ch == '\t' || ch == ':' ) { + /* nop */ + } else if( ch == '\'' ) { /* comment */ + st_rem(); + } else if( ch == '@' ) { /* is it l-value? */ + SHORT * pvar; + pvar = getArrayReference(); + if( pvar == NULL ) return; + st_assignment( pvar ); + } else if( ch >= 'A' && ch <= 'Z' ) { + st_assignment( &globalVariables[ch-'A'] ); + } else if( ch >= 'a' && ch <= 'z' ) { + st_assignment( &localVariables[ch-'a'] ); + } else if( ch >= KEYWORDS_STATEMENT_FROM && ch <= KEYWORDS_STATEMENT_TO ) { + (*(statements[ch-KEYWORDS_STATEMENT_FROM]))(); + } else { + syntaxError(); + } + if( bForceToReturnSuper ) return; + } + if( bInteractive ) return; + } +} + +void interactiveMain( FILE FAR * fp ) +{ + if( fp == NULL ) { + commonPrint(NULL,"*Ready\n"); + } + while( TRUE ) { + BOOL b; + if( fp == NULL ) { + consoleInput( waRawLine, LINE_SIZE ); + } else { + char FAR * r; + char * p; + r = fgets( waRawLine, LINE_SIZE, fp ); + if( r == NULL ) break; + p = waRawLine; + while( TRUE ) { + if( *p == '\0' ) break; + if( *p == '\n' || *p == '\r') { + *p = '\0'; + break; + } + p++; + } + } +#ifdef WW + if( fp == NULL ) { + commonPrint( NULL, "\r\n" ); + } +#endif + /* 中間言語に翻訳する */ + b = convertInternalCode( waCoockedLine, waRawLine ); + if( b == FALSE ) { + bForceToReturnSuper = FALSE; + continue; + } + /* 数値で開始されているか? */ + if( waCoockedLine[0] == 0x01 ) { + /* 行エディタを呼び出す */ + editLine(); + } else { + /* その行を実行する */ + executionPointer = waCoockedLine; + interpreterMain(); + } + if( bForceToReturnSuper ) return; + } +} + +/* プログラムの実行開始 */ +void do_run( WORD runLineNumber ) +{ + BYTE * target; + if( runLineNumber == 0 ) { + target = &wa[codeTop]; + } else { + target = getLineReferenceFromLineNumber( runLineNumber ); + if( target == NULL ) { + lineNumberNotFound( runLineNumber ); + return; + } + } + clearRuntimeInfo(); + bInteractive = FALSE; + executionPointer = target; +} + +void do_new() +{ + clearRuntimeInfo(); + bInteractive = TRUE; + codeTop = 0; + wa[0] = 0; + wa[1] = 0; + wa[2] = EOL; + dataTop = 3; +} + +BOOL do_merge( const BYTE * filename ) +{ + FILE FAR * fp; + fp = fopen( filename, "r" ); + if( fp == NULL ) { + loadError(); + return FALSE; + } + interactiveMain( fp ); + fclose( fp ); + if( bForceToReturnSuper ) return FALSE; + return TRUE; +} + +void superMain() +{ + while( TRUE ) { + BOOL b; + bForceToReturnSuper = FALSE; + switch( requestNextAction ) { + case REQUEST_INTERACTIVE: + bInteractive = TRUE; + break; + case REQUEST_RUN_LINENUMBER: + do_run( runLineNumber ); + break; + case REQUEST_RUN_FILE: + do_new(); + b = do_merge( waRawLine ); + if( b ) { + do_run( 0 ); + } + break; + case REQUEST_LOAD_FILE: + do_new(); + do_merge( waRawLine ); + break; + case REQUEST_MERGE_FILE: + do_merge( waRawLine ); + break; + case REQUEST_NEW: + do_new(); + break; + case REQUEST_EXIT_SYSTEM: + return; + } + requestNextAction = REQUEST_NO_ACTION; + if( bInteractive ) { + if( runtimeOnly ) return; /* ランタイムモードのときは絶対にインタラクティブモードに行かない */ + interactiveMain( NULL ); + } else { + interpreterMain(); + } + bForceToReturnSuper = FALSE; + } +} + +#ifdef WW +BOOL entranceUI() +{ +#define MAX_ENT 15 + /* この関数内のstaticはTurbo-C 2.0のSS!=DS問題を回避するために必要なもの */ + static int i; + struct stat statbuf; + static char names[MAX_ENT][MAXFNAME]; + static int nent; + static int c, select; + + ptextCLS(); + ptextString( "ワンべぇ V" ); + ptextString( myVersion ); + ptextNewline(); + ptextString( "↑↓Aでファイル選択 Y2で開発環境 STARTで中止" ); + + c = 0; + nent = nument(NULL); + + for (i = 0; i < nent; i++) { + int result; + if( c >= MAX_ENT ) break; + result = getent(NULL, i, &statbuf); + if (result == E_FS_SUCCESS) { + if (statbuf.count != -1) { + /* Freya OSのバグ? 回避コード */ + { + static int p; + int q; + p = 0; + q = 0; + waRawLine[p++] = statbuf.info[q++]; + waRawLine[p++] = statbuf.info[q++]; + while( TRUE ) { + if( statbuf.info[q] == '\0' ) break; + waRawLine[p++] = statbuf.info[q++]; + } + waRawLine[p++] = '\0'; + ptextLocate(1,c+2); + ptextString( waRawLine ); + } + { + static int r; + int q; + q = 0; + r = 0; + while( TRUE ) { + if( statbuf.name[q] == '\0' ) break; + names[c][r++] = statbuf.name[q++]; + } + names[c][r] = '\0'; + } + c++; + } + } + } + /* 選択の開始 */ + select = 0; + while( TRUE ) { + int key; + for( i=0; i= c ) { + select = 0; + } + } + if( (key & 0x200) != 0 ) { + return TRUE; + } + } +} +#endif + +int main( int argc, char *argv[] ) +{ +#ifdef WW + BOOL b; +#endif + runtimeOnly = FALSE; + requestNextAction = REQUEST_NO_ACTION; +#ifdef WIN32 + createText(); +#endif +#ifdef WW + text_screen_init(); + b = entranceUI(); + if( b == FALSE ) return 0; + if( !runtimeOnly ) { + comm_set_baudrate(1); + comm_open(); + } +#endif + ptextCLS(); + if( requestNextAction == REQUEST_NO_ACTION ) { + do_new(); + } + if( !runtimeOnly ) { + commonPrint(NULL,"ワンべぇ WonderWitch Tiny BASIC Environment Ver %s\n",myVersion); + commonPrint(NULL,"Copyright 2000 (c) by Pie Dey Co.,Ltd.\n"); + } + superMain(); +#ifdef WIN32 + deleteText(); +#endif +#ifdef WW + if( !runtimeOnly ) { + comm_close(); + } +#endif + return 0; +} + +/* end of wonbe.c */ diff --git a/wonbe.cf b/wonbe.cf new file mode 100644 index 0000000..952b04c --- /dev/null +++ b/wonbe.cf @@ -0,0 +1 @@ +name: wonbe info: ワンべぇ mode: 7 source: wonbe.bin output: wonbe.fx \ No newline at end of file diff --git a/wonbe.dsp b/wonbe.dsp new file mode 100644 index 0000000..e4b2825 --- /dev/null +++ b/wonbe.dsp @@ -0,0 +1,112 @@ +# Microsoft Developer Studio Project File - Name="wonbe" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** 編集しないでください ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=wonbe - Win32 Debug +!MESSAGE これは有効なメイクファイルではありません。 このプロジェクトをビルドするためには NMAKE を使用してください。 +!MESSAGE [メイクファイルのエクスポート] コマンドを使用して実行してください +!MESSAGE +!MESSAGE NMAKE /f "wonbe.mak". +!MESSAGE +!MESSAGE NMAKE の実行時に構成を指定できます +!MESSAGE コマンド ライン上でマクロの設定を定義します。例: +!MESSAGE +!MESSAGE NMAKE /f "wonbe.mak" CFG="wonbe - Win32 Debug" +!MESSAGE +!MESSAGE 選択可能なビルド モード: +!MESSAGE +!MESSAGE "wonbe - Win32 Release" ("Win32 (x86) Console Application" 用) +!MESSAGE "wonbe - Win32 Debug" ("Win32 (x86) Console Application" 用) +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wonbe - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x411 /d "NDEBUG" +# ADD RSC /l 0x411 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "wonbe - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x411 /d "_DEBUG" +# ADD RSC /l 0x411 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "wonbe - Win32 Release" +# Name "wonbe - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\win32text.c +# End Source File +# Begin Source File + +SOURCE=.\wonbe.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\keywords.h +# End Source File +# Begin Source File + +SOURCE=.\win32text.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/wonbe.dsw b/wonbe.dsw new file mode 100644 index 0000000..fa22673 --- /dev/null +++ b/wonbe.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# 警告: このワークスペース ファイル を編集または削除しないでください! + +############################################################################### + +Project: "wonbe"=.\wonbe.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/wonbe.exe b/wonbe.exe new file mode 100644 index 0000000000000000000000000000000000000000..a89cd1dd3eff1ffe66b88d213aea9c5b38f76993 GIT binary patch literal 53248 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 VKxdOD-p`j#MhesWhyKH*{|4NH!-fC= literal 0 HcmV?d00001 diff --git a/wonbe.txt b/wonbe.txt new file mode 100644 index 0000000..2a58ec7 --- /dev/null +++ b/wonbe.txt @@ -0,0 +1,226 @@ +ワンべぇ: WONBE, WonderWitch BASIC Environment + 暫定マニュアル Ver 0.01 + 2000年11月6日 + 株式会社ピーデー + 川俣 晶 + Copyright 2000 (c) by Pie Dey Co.Ltd. + +●これは何か? + ワンべぇは、WonderWitch上で使用できる小型BASICインタプリタです。 + WonderWitch上ですべての機能が稼働し、シリアルケーブル経由で接続された一般の通信ソフトで操作します。デバッグ済みのプログラムを実行する場合は、シリアルケーブルも通信ソフトも必要ありません。 + WonderWitchのテキスト画面を扱う最小限度のステートメント(cls,locate,print)と、最小限度のボタン入力機能(wait,scan)を持ち、簡易なミニゲームが書けます。 + 動作テスト用にWin32上で動くバイナリーもありますが、これは、BASIC本体の動作確認用と割り切ってください。 + +●必要なもの +・開発時 + WonderWitchのカートリッジとシリアルケーブル。38400bpsの無手順通信が可能な通信ソフトを持つパソコン等。 +・実行時 + ワンべぇと実行したプログラムを入れてあるWonderWitchのカートリッジのみ + +●準備 +・TransMagicなどでワンべぇ(fonbe.fx)をWonderWitchに転送します。 +・TransMagicなどの接続を切り、通信ソフトから38400bpsの無手順通信を開始します +・WonderWitch上でワンべぇを実行します +・エントランスメニュー画面でY2を押します +・通信ソフトに、ワンべぇの名前が表示され、"*Ready"と出ます +・これで準備完了です +・print "hello!"リターンと打ってWonderWitchの画面を見てください。文字が出ていれば正常です。 + +●開発済みプログラムの実行 +・WonderWitch上でワンべぇを実行します +・エントランスメニュー画面で実行したいファイルを選んでAボタンを押します + +●開発環境の概要 + 通常の行番号ベースのエディタが使えます。 + 行番号に引き続いて1行を入力してリターンを押すと、プログラムに記録されます。 + 行番号だけを入力してリターンを押すとその行は削除されます。 + 行番号無しで命令を入力すると即座に実行されます。 + 編集はバックスペースによる1文字削除しか使えません。通信ソフトからホスト上のエディタにCOPY&PASTEして、エディタ上で編集してから、通信ソフトに貼り付けてワンべぇに送ると便利です。ただし、フロー制御が無いので、複数行まとめて貼り付けると文字落ちが生じます。張り付けは1行単位で行ってください。プログラムはホスト上で編集してあらかじめTransMagicなどで送信しておくのも有効な手段です。 + 現状では2Kバイト以上のプログラムを作成してもsaveコマンドで保存できません。listコマンドを実行してから通信ソフト上でCOPY&PASTEしてホスト上に保存してください。 + 実行中は、STARTボタンを押すといつでも対話モードに戻れます。その後、contステートメントで実行を継続できます。 + 中間言語に翻訳してから処理するため、中間言語に翻訳できない場合は、入力直後にエラーが出ます。 + +●言語の概要 + ごく軽いBASIC言語です。 + 昔あったTiny BASICに近い構文を持っています。 + データ型は、符号付き16bit整数だけです。 + 定数は、-32768〜32767の10進数か、0x0000〜0xffffの16進数で記述できます。 + 変数は、グローバル変数として、A〜Zのアルファベット大文字1文字のものが26個あります。 + ローカル変数として、a〜zのアルファベット子文字1文字のものが26個あります。ローカル変数はgosubステートメントを実行したときに新しい領域が割り当てられ、returnステートメントを実行したときにgosubする前の領域が戻ってきます。 + 配列変数は@(インデックス)という形式の1次元配列だけが使用できます。使用可能なサイズは、プログラム記憶領域(48Kバイト)の残りサイズに等しくなります。インデックスは0から始まります。(例: for i=0 to 9:print @(i):next) + 演算子の優先順位はありません。(1+2*3は9になります) + 計算順序は、括弧()を使って明示的にコントロールしてください。 + オーバーフロー、アンダーフローのチェックはありません。溢れは無視されます。ただしゼロ除算はエラーになります。 + ステートメントなどのキーワードはすべてアルファベット小文字で入力します。大文字を使っても小文字になります。 + +● ステートメント一覧 + +変数 = 式 + 式を計算して変数に代入します。letキーワードはサポートしていません。 +例: a=b+c + +if 式 then ステートメント列 + 式が0でなければステートメント列を実行します。0なら次の行から実行を継続します。elseはありません。 +例: if (a=0) and (b=1) then goto 200 + +print [文字列|式|chr(式)][,|;]... + WonderWitchのテキスト画面の現在のカーソル位置から文字を表示します。 + 式の前後に空白文字が入ることはありません。 + chr(式)は、式の値を文字コードと見なして表示します。 + 制御コードは扱いませんので、WonderWitchのキャラクタージェネレータにあるすべての文字が表示できます。 + 区切り文字の;は何もしません。,はタブストップ位置までカーソルを進めます。 + print文の最後は;または,で終わった場合は改行しません。 +例: print "計算結果=",chr(34);1+2;chr(34) + +locate 式,式 + WonderWitchのテキスト画面の現在のカーソル位置を設定します。引数はx,yの順番です。 +例: locate 10,10 + +cls + WonderWitchのテキスト画面を消去します。 +例: cls + +goto 式 + 式の行番号に飛びます。計算型goto文が可能です。つまり、goto A*100とすると、Aが1のきは100行目に。2のときは200行目に飛びます。 +例: goto 100 + +gosub 式 + スタックに現在位置とローカル変数を積んで、式の行番号に飛びます。gotoと同じく計算型gosubが可能です。 + スタックはforと合わせて8レベルまでです。 +例: gosub 100 + +return + gosubがスタックに積んだ情報を取り出して、そこに処理を戻す。ローカル変数も戻る。 +例: return + +for 変数=式 to 式 +for 変数=式 to 式 step 式 + 変数の値を変化させながらnextまで繰り返します。 + 終了値は厳密であることに注意が必要です。for i=1 to 2 step 2:nextは、無限ループになります。なぜなら変数iは永遠に2にならないからです。このような仕様にしておかないと、終了値を超えたら終わるという判定だと、ループの終値が32767のときに機能しないためです。 +例: for i=0 to 10 step 2 + +next + forステートメントの位置に戻って動作を繰り返します。forステートメントで示した条件が満たされた場合は、nextの次に動作が進みます。nextの後に変数名を書くとエラーになります。 +例: next + +end + プログラムの実行を終了します。 + +break + その位置で一時的に実行を中断します。contステートメントで実行を継続できます。 + +rem 文字列 +'文字列 + コメントを記述します。後ろに:を置いてステートメントを続けることはできません。 +例: rem これはテストプログラムです。 +例: 'この式が座標を計算します + +new + メモリ上のプログラムを消去します。 + +list [行番号][-][行番号] + 指定範囲の行番号のプログラムをリストします。すべて省略すると全行をリストします。 + +run +run 式 +run 文字列 + プログラムを実行します。それに先だって変数やスタックがクリアされます。 + runはメモリ上のプログラムを先頭から。run 式は、式の行番号から。run 文字列は文字列のファイルを読み込んでそれを実行します。 +例: run +例: run 100 +例: run "test.wb" + +cont + breakステートメントやSTARTボタンによるブレークによって停止した位置から実行を再開します。 + +save 文字列 + 文字列をファイル名としてメモリ上のプログラムを保存します。保存されるのは内部表現ではなくテキスト形式です。 + 現在はWonderWitchのファイルシステムの制約上、2Kバイトを超えるファイルを保存できません。listコマンドで端末にリストを送ってそれをCOPY&PASTEして保存してください。 +例: save "hello.wb" + +load 文字列 + 文字列をファイル名としてファイルからプログラムを読み込みます。読み込むのはテキスト形式で、改行はCRLFとLFのどちらでも可です。中間言語に翻訳できない行がある場合はそこで読み込みが中断されます。プログラムの実行中に使用した場合は実行は中断されます。 +例: load "hello.wb" + +merge 文字列 + メモリ上のプログラムにファイル上のプログラムを混ぜ合わせます。同じ行番号の行は読み込まれる方が優先されます。中間言語に翻訳できない行がある場合はそこで読み込みが中断されます。プログラムの実行中に使用した場合は実行は中断されます。 +例: load "merge.wb" + +randomize 式 + 乱数の初期値を指定します。これを使わないと必ず同じ順序で乱数が発生します。引数には、システム変数tickを指定すると最適です。 +例: randomize tick + +exit + ワンべぇを抜けてOSに戻ります。 + +debug [文字列|式|chr(式)][,|;]... + printステートメントと同等ですが、WonderWitchの画面ではなく、シリアルポートに送ります。単体で実行する場合には使えないデバッグ専用の機能です。 + +waitvb 式 + 式の回数だけVBLANKを待ちます。待っている間はSTARTボタンによるブレークを受け付けなくなるので、指定できる値は750までと制限されています。750を超える値を指定するとエラーになります。 +例: waitvb 75 + +files + カレントディレクトリのファイル一覧をシリアルポートに送ります。単体で実行する場合には使えないデバッグ専用の機能です。 + +● 2項演算子 + + - * / < > = <= >= <> and or xor + +● 単項演算子 + - not + +● 関数 + +rnd(式) + 0から式-1までの範囲の乱数を返します。 + +abs(式) + 式の絶対値を返します。 + +● システム変数 (読み出しのみ) + +scan + WonderSwanのボタンの状態を調べ、1個の整数値として返します。SCAN_で始まるシステム変数とandを取ることで、どのボタンが押されているかどうか判定できます。STARTボタンは実行中断になるので、これは扱えません。 + +wait + WonderSwanのボタンが押されるまで待ち、その状態を1個の整数値として返します。SCAN_で始まるシステム変数とandを取ることで、どのボタンが押されたか判定できます。STARTボタンは実行中断になるので、これは扱えません。 + +scan_a +scan_b +scan_x1 +scan_x2 +scan_x3 +scan_x4 +scan_y1 +scan_y2 +scan_y3 +scan_y4 + それぞれのボタンのマスク値を示す定数を返します。 + Aボタンが押されているかどうかを調べるには、下記の例のように記述します。 +例: if scan and scna_a then print "Aボタンが押さている" + +tick + システムタイマーのtickを返します。ただし、本来のtick値は符号無し32bit整数であり、ここで得られるのは16bit符号あり整数であることに注意が必要です。はみ出たbitは捨てられます。 + +● ファイル保存時の拡張子 + 一応、ワンべぇのソースフィルは、".wb"で終わるファイル名にしておいて下さい。現在エントランスメニューには全ファイルが見えていますが、".wb"で終わるファイル名だけに限定しようかと考えています。 + +● 配布規則 + 現バージョンは品質が不明のテスト版です。 + ですので、以下のように扱ってください。 + (正規版でどうするかは未定です) + +・転載 + 未完成品ですので、Internetやパソコン通信などへの転載は不可です。必ずhttp://www.piedey.co.jp/のサイトから入手するようにしてください。 +・雑誌掲載等 + ご相談下さい。 +・商業利用 + ご相談下さい。 +・自作ソフトの実行手段としてのワンべぇの添付 + 自作ソフトを配布するためにwonbe.fxを一緒に渡すことを許可します。アーカイブへの同梱、CD-Rメディアなどへの焼き込み、通信ケーブルによる転送、どれも可です。ただし、ワンべぇの動作に関しては何も保証はできませんので、リスクは自分で負ってください。利用にあたっては、ロイヤリティなどはありませんので、報告も送金も必要ありません。 + +● 問い合わせ先 +株式会社ピーデー http://www.piedey.co.jp/ +川俣 晶 autumn@piedey.co.jp + +以上