ChipMaster's bwBASIC This also includes history going back to v2.10. *WARN* some binary files might have been corrupted by CRLF.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3632 lines
88 KiB

  1. /***************************************************************
  2. bwbasic.c Main Program File
  3. for Bywater BASIC Interpreter
  4. Copyright (c) 1993, Ted A. Campbell
  5. Bywater Software
  6. email: tcamp@delphi.com
  7. Copyright and Permissions Information:
  8. All U.S. and international rights are claimed by the author,
  9. Ted A. Campbell.
  10. This software is released under the terms of the GNU General
  11. Public License (GPL), which is distributed with this software
  12. in the file "COPYING". The GPL specifies the terms under
  13. which users may copy and use the software in this distribution.
  14. A separate license is available for commercial distribution,
  15. for information on which you should contact the author.
  16. ***************************************************************/
  17. /*---------------------------------------------------------------*/
  18. /* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */
  19. /* 11/1995 (eidetics@cerf.net). */
  20. /* */
  21. /* Those additionally marked with "DD" were at the suggestion of */
  22. /* Dale DePriest (daled@cadence.com). */
  23. /* */
  24. /* Version 3.00 by Howard Wulf, AF5NE */
  25. /* */
  26. /* Version 3.10 by Howard Wulf, AF5NE */
  27. /* */
  28. /*---------------------------------------------------------------*/
  29. #include "bwbasic.h"
  30. GlobalType * My = NULL;
  31. static char * DefaultErrorMessage[ 80 ] =
  32. {
  33. /* 00 */ ""
  34. , /* 01 */ "NEXT without FOR"
  35. , /* 02 */ "Syntax error"
  36. , /* 03 */ "RETURN without GOSUB"
  37. , /* 04 */ "Out of DATA"
  38. , /* 05 */ "Illegal function call"
  39. , /* 06 */ "Overflow"
  40. , /* 07 */ "Out of memory"
  41. , /* 08 */ "Undefined line"
  42. , /* 09 */ "Subscript out of range"
  43. , /* 10 */ "Redimensioned array"
  44. , /* 11 */ "Division by zero"
  45. , /* 12 */ "Illegal direct"
  46. , /* 13 */ "Type mismatch"
  47. , /* 14 */ "Out of string space"
  48. , /* 15 */ "String too long"
  49. , /* 16 */ "String formula too complex"
  50. , /* 17 */ "Can't continue"
  51. , /* 18 */ "Undefined user function"
  52. , /* 19 */ "No RESUME"
  53. , /* 20 */ "RESUME without error"
  54. , /* 21 */ "Unprintable error"
  55. , /* 22 */ "Missing operand"
  56. , /* 23 */ "Line buffer overflow"
  57. , /* 24 */ ""
  58. , /* 25 */ ""
  59. , /* 26 */ "FOR without NEXT"
  60. , /* 27 */ ""
  61. , /* 28 */ ""
  62. , /* 29 */ "WHILE without WEND"
  63. , /* 30 */ "WEND without WHILE"
  64. , /* 31 */ "EXIT FUNCTION without FUNCTION"
  65. , /* 32 */ "END FUNCTION without FUNCTION"
  66. , /* 33 */ "EXIT SUB without SUB"
  67. , /* 34 */ "END SUB without SUB"
  68. , /* 35 */ "EXIT FOR without FOR"
  69. , /* 36 */ ""
  70. , /* 37 */ ""
  71. , /* 38 */ ""
  72. , /* 39 */ ""
  73. , /* 40 */ ""
  74. , /* 41 */ ""
  75. , /* 42 */ ""
  76. , /* 43 */ ""
  77. , /* 44 */ ""
  78. , /* 45 */ ""
  79. , /* 46 */ ""
  80. , /* 47 */ ""
  81. , /* 48 */ ""
  82. , /* 49 */ ""
  83. , /* 50 */ "Field overflow"
  84. , /* 51 */ "Internal error"
  85. , /* 52 */ "Bad file number"
  86. , /* 53 */ "File not found"
  87. , /* 54 */ "Bad file mode"
  88. , /* 55 */ "File already open"
  89. , /* 56 */ ""
  90. , /* 57 */ "Disk I/O error"
  91. , /* 58 */ "File already exists"
  92. , /* 59 */ ""
  93. , /* 60 */ ""
  94. , /* 61 */ "Disk full"
  95. , /* 62 */ "Input past end"
  96. , /* 63 */ "Bad record number"
  97. , /* 64 */ "Bad file name"
  98. , /* 65 */ ""
  99. , /* 66 */ "Direct statement in file"
  100. , /* 67 */ "Too many files"
  101. , /* 68 */ ""
  102. , /* 69 */ ""
  103. , /* 70 */ "Variable Not Declared"
  104. , /* 71 */ ""
  105. , /* 72 */ ""
  106. , /* 73 */ "Advanced Feature"
  107. , /* 74 */ ""
  108. , /* 75 */ ""
  109. , /* 76 */ ""
  110. , /* 77 */ ""
  111. , /* 78 */ ""
  112. , /* 79 */ ""
  113. };
  114. static char *Banner[] = {
  115. "######## ## ## ## ## ### ######## ######## ######## ",
  116. "## ## ## ## ## ## ## ## ## ## ## ## ## ",
  117. "## ## #### ## ## ## ## ## ## ## ## ## ",
  118. "######## ## ## ## ## ## ## ## ###### ######## ",
  119. "## ## ## ## ## ## ######### ## ## ## ## ",
  120. "## ## ## ## ## ## ## ## ## ## ## ## ",
  121. "######## ## ### ### ## ## ## ######## ## ## ",
  122. " ",
  123. " ",
  124. " ######## ### ###### #### ###### ",
  125. " ## ## ## ## ## ## ## ## ##",
  126. " ## ## ## ## ## ## ## ",
  127. " ######## ## ## ###### ## ## ",
  128. " ## ## ######### ## ## ## ",
  129. " ## ## ## ## ## ## ## ## ##",
  130. " ######## ## ## ###### #### ###### ",
  131. " ",
  132. "Bywater BASIC Interpreter, version 3.10 ",
  133. "Copyright (c) 1993, Ted A. Campbell ",
  134. "Copyright (c) 1995-1997, Jon B. Volkoff ",
  135. "Copyright (c) 2014-2016, Howard Wulf, AF5NE ",
  136. " ",
  137. NULL
  138. };
  139. int
  140. bwx_DEBUG(const char *A)
  141. {
  142. /*
  143. ** -- RECURSION WARNING --
  144. ** -- DO NOT SEND IT TO BACK TO BWBASIC --
  145. ** This is DEBUG output.
  146. ** Send it to a file, OutputDebugString, or fputs()
  147. */
  148. if (My->MaintainerDebugOn)
  149. {
  150. if (My->MaintainerDebugFile == NULL)
  151. {
  152. My->MaintainerDebugFile = fopen(DEBUGFILENAME, "w");
  153. }
  154. if (My->MaintainerDebugFile != NULL)
  155. {
  156. fputs(A, My->MaintainerDebugFile);
  157. fputs("\n", My->MaintainerDebugFile);
  158. fflush(My->MaintainerDebugFile);
  159. }
  160. else
  161. {
  162. /* unable to open DEBUG file, so send the message to My->SYSOUT->cfp */
  163. if( My->SYSOUT != NULL )
  164. {
  165. if( My->SYSOUT->cfp != NULL )
  166. {
  167. fputs( A, My->SYSOUT->cfp );
  168. fputs( "\n", My->SYSOUT->cfp );
  169. fflush( My->SYSOUT->cfp );
  170. }
  171. }
  172. }
  173. }
  174. return 0;
  175. }
  176. /***************************************************************
  177. FUNCTION: bwx_terminate()
  178. DESCRIPTION: This function terminates program execution.
  179. ***************************************************************/
  180. void
  181. bwx_terminate(void)
  182. {
  183. bwx_DEBUG(__FUNCTION__);
  184. exit(0);
  185. }
  186. /***************************************************************
  187. FUNCTION: break_handler()
  188. DESCRIPTION: This function is called by break_mes()
  189. and handles program interruption by break
  190. (or by the STOP command).
  191. ***************************************************************/
  192. void
  193. break_handler(void)
  194. {
  195. bwx_DEBUG(__FUNCTION__);
  196. My->AutomaticLineNumber = 0;
  197. My->AutomaticLineIncrement = 0;
  198. if (My->IsInteractive)
  199. {
  200. /* INTERACTIVE: terminate program */
  201. /* reset all stack counters */
  202. bwb_clrexec();
  203. SetOnError(0);
  204. My->err_number = -1; /* in break_handler() */
  205. /* reset the break handler */
  206. signal(SIGINT, break_mes);
  207. longjmp(My->mark, -1);
  208. return;
  209. }
  210. /* NOT INTERACTIVE: terminate immediately */
  211. bwx_terminate();
  212. }
  213. /***************************************************************
  214. FUNCTION: break_mes()
  215. DESCRIPTION: This function is called (a) by a SIGINT
  216. signal or (b) by bwb_STOP via bwx_STOP.
  217. It prints an error message then calls
  218. break_handler() to terminate the program.
  219. ***************************************************************/
  220. void
  221. break_mes(int x /* Parameter 'x' is never used */ )
  222. {
  223. /* break_mes() is FATAL */
  224. bwx_DEBUG(__FUNCTION__);
  225. if (My->err_number < 0) /* do not make a bad situation worse */
  226. {
  227. /* an error has already ben reported */
  228. }
  229. else
  230. {
  231. prn_xprintf("\n");
  232. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
  233. {
  234. if( is_empty_filename( My->progfile ) == FALSE )
  235. {
  236. prn_xprintf("FILE:");
  237. prn_xprintf(My->progfile);
  238. prn_xprintf(", ");
  239. }
  240. }
  241. prn_xprintf("Program interrupted at line");
  242. if( My->ThisLine != NULL )
  243. {
  244. if ( BasicLineNumberMin <= My->ThisLine->number && My->ThisLine->number <= BasicLineNumberMax )
  245. {
  246. char tbuf[33];
  247. sprintf(tbuf, "%d", My->ThisLine->number);
  248. prn_xprintf(" ");
  249. prn_xprintf(tbuf);
  250. }
  251. }
  252. prn_xprintf("\n");
  253. }
  254. break_handler();
  255. }
  256. void
  257. bwx_STOP(void)
  258. {
  259. bwx_DEBUG(__FUNCTION__);
  260. break_mes(0);
  261. }
  262. /***************************************************************
  263. FUNCTION: bwx_signon()
  264. DESCRIPTION: This function prints out the sign-on
  265. message for bwBASIC.
  266. ***************************************************************/
  267. int
  268. bwx_signon(void)
  269. {
  270. /* NOT called if a file is provided on the command line */
  271. int i;
  272. bwx_DEBUG(__FUNCTION__);
  273. for (i = 0; Banner[i] != NULL; i++)
  274. {
  275. prn_xprintf(Banner[i]);
  276. prn_xprintf("\n");
  277. }
  278. return TRUE;
  279. }
  280. BasicNumberType
  281. bwx_TIMER(BasicNumberType Seconds)
  282. {
  283. /* Return a number representing Seconds in the future. Seconds >= 0.
  284. * Seconds may be non-integer, such as 0.001 or 86399.999. The
  285. * maximum allowed Seconds is DBL_MAX. This is used two ways: 1) in
  286. * bwb_TIMER(), the ON TIMER count (>0) is used to determine the
  287. * expiration time. In this case, simply return what the value will
  288. * be in the future. Note that ON TIMER enforces Seconds > (1 /
  289. * CLOCKS_PER_SEC) 2) in bwb_execline(), zero (=0) is used to
  290. * determine the current time and compare it to #1. In this case,
  291. * simply return what the value is now. Both the resolution of the
  292. * timer, and frequency of update, are implementation defined. */
  293. bwx_DEBUG(__FUNCTION__);
  294. if (Seconds < 0)
  295. {
  296. WARN_INTERNAL_ERROR;
  297. return 0;
  298. }
  299. else
  300. {
  301. BasicNumberType Result;
  302. Result = clock();
  303. Result /= CLOCKS_PER_SEC;
  304. Result += Seconds;
  305. return Result;
  306. }
  307. }
  308. void
  309. CleanLine(char *buffer)
  310. {
  311. /* cleanup the line, so it is easier to parse */
  312. char *newbuffer;
  313. bwx_DEBUG(__FUNCTION__);
  314. if( buffer == NULL )
  315. {
  316. /* do nothing */
  317. return;
  318. }
  319. if( buffer[0] == BasicNulChar )
  320. {
  321. /* do nothing */
  322. return;
  323. }
  324. /* remove CR/LF */
  325. newbuffer = bwb_strchr( buffer, '\r' );
  326. if( newbuffer != NULL )
  327. {
  328. *newbuffer = BasicNulChar;
  329. }
  330. newbuffer = bwb_strchr( buffer, '\n' );
  331. if( newbuffer != NULL )
  332. {
  333. *newbuffer = BasicNulChar;
  334. }
  335. /* remove ALL embedded control characters */
  336. /* if you want a control character, then use CHR$ */
  337. newbuffer = buffer;
  338. while (*newbuffer != BasicNulChar)
  339. {
  340. if( bwb_isprint( *newbuffer ) )
  341. {
  342. /* OK */
  343. }
  344. else
  345. {
  346. *newbuffer = ' ';
  347. }
  348. newbuffer++;
  349. }
  350. /* LTRIM$ */
  351. newbuffer = buffer;
  352. if (*newbuffer != BasicNulChar)
  353. {
  354. /* not an empty line, so remove one (or more) leading spaces */
  355. while (*newbuffer == ' ')
  356. {
  357. newbuffer++;
  358. }
  359. if (newbuffer > buffer)
  360. {
  361. bwb_strcpy(buffer, newbuffer);
  362. }
  363. }
  364. /* RTRIM$ */
  365. newbuffer = buffer;
  366. if (*newbuffer != BasicNulChar)
  367. {
  368. /* not an empty line, so remove one (or more) trailing spaces */
  369. char *E;
  370. E = bwb_strchr(newbuffer, BasicNulChar);
  371. E--;
  372. while (E >= newbuffer && *E == ' ')
  373. {
  374. *E = BasicNulChar;
  375. E--;
  376. }
  377. }
  378. }
  379. /***************************************************************
  380. FUNCTION: bwb_init()
  381. DESCRIPTION: This function initializes bwBASIC.
  382. ***************************************************************/
  383. void
  384. bwb_init( void )
  385. {
  386. register int n;
  387. static char start_buf[] = "\0";
  388. static char end_buf[] = "\0";
  389. bwx_DEBUG(__FUNCTION__);
  390. My->IsCommandLineFile = FALSE;
  391. My->ExternalInputFile = NULL; /* for automated testing, TAPE command */
  392. My->IsPrinter = FALSE; /* CBASIC-II: CONSOLE and LPRINTER commands */
  393. bwb_strcpy( My->progfile, "" );
  394. bwb_memset( &My->bwb_start, 0, sizeof(LineType) );
  395. bwb_memset( &My->bwb_end , 0, sizeof(LineType) );
  396. bwb_memset( &My->user_line, 0, sizeof(LineType) );
  397. My->bwb_start.number = BasicLineNumberMin - 1;
  398. My->bwb_start.next = &My->bwb_end;
  399. My->bwb_start.position = 0;
  400. My->bwb_start.buffer = start_buf;
  401. My->bwb_end.number = BasicLineNumberMax + 1;
  402. My->bwb_end.next = &My->bwb_end;
  403. My->bwb_end.position = 0;
  404. My->bwb_end.buffer = end_buf;
  405. My->user_line.number = BasicLineNumberMin - 1;
  406. My->user_line.next = &My->bwb_end;
  407. My->user_line.position = 0;
  408. My->user_line.buffer = NULL;
  409. My->data_line = &My->bwb_start;
  410. My->data_pos = 0;
  411. My->stack_head = NULL;
  412. My->stack_level = 0;
  413. My->field_head = NULL;
  414. #if NEW_VIRTUAL
  415. My->virtual_head = NULL;
  416. #endif /* NEW_VIRTUAL */
  417. My->ThisLine = &My->bwb_start;
  418. SortAllCommands();
  419. SortAllFunctions();
  420. SortAllOperators();
  421. /* Memory allocation */
  422. if ((My->bwb_ebuf = CALLOC(BasicStringLengthMax + 1, sizeof(char), "bwb_init")) == NULL)
  423. {
  424. WARN_OUT_OF_MEMORY;
  425. return;
  426. }
  427. if ((My->read_line = CALLOC(BasicStringLengthMax + 1, sizeof(char), "bwb_init")) == NULL)
  428. {
  429. WARN_OUT_OF_MEMORY;
  430. return;
  431. }
  432. if ((My->SYSIN = CALLOC(1, sizeof(FileType), "bwb_init")) == NULL)
  433. {
  434. WARN_OUT_OF_MEMORY;
  435. return;
  436. }
  437. if ((My->SYSOUT = CALLOC(1, sizeof(FileType), "bwb_init")) == NULL)
  438. {
  439. WARN_OUT_OF_MEMORY;
  440. return;
  441. }
  442. if ((My->SYSPRN = CALLOC(1, sizeof(FileType), "bwb_init")) == NULL)
  443. {
  444. WARN_OUT_OF_MEMORY;
  445. return;
  446. }
  447. /* initialize tables of variables, functions */
  448. var_init();
  449. fnc_init();
  450. fslt_init();
  451. OptionVersionSet(0);
  452. My->SYSIN->mode = DEVMODE_INPUT;
  453. My->SYSIN->width = 80;
  454. My->SYSIN->col = 1;
  455. My->SYSIN->row = 1;
  456. My->SYSIN->delimit = ',';
  457. My->SYSIN->cfp = stdin;
  458. My->SYSOUT->mode = DEVMODE_OUTPUT;
  459. My->SYSOUT->width = 80;
  460. My->SYSOUT->col = 1;
  461. My->SYSOUT->row = 1;
  462. My->SYSOUT->delimit = ',';
  463. My->SYSOUT->cfp = stdout;
  464. My->SYSPRN->mode = DEVMODE_OUTPUT;
  465. My->SYSPRN->width = 80;
  466. My->SYSPRN->col = 1;
  467. My->SYSPRN->row = 1;
  468. My->SYSPRN->delimit = ',';
  469. My->SYSPRN->cfp = stderr;
  470. My->LPRINT_NULLS = 0;
  471. My->SCREEN_ROWS = 24;
  472. /* OPEN #0 is an ERROR. */
  473. /* CLOSE #0 is an ERROR. */
  474. /* WIDTH #0, 80 is the same as WIDTH 80. */
  475. /* LPRINT and LLIST are sent to bwx_LPRINT() */
  476. /* default variable type */
  477. for (n = 0; n < 26; n++)
  478. {
  479. My->DefaultVariableType[n] = BasicDoubleSuffix;
  480. }
  481. /* default COMMAND$(0-9) */
  482. for( n = 0; n < 10; n++ )
  483. {
  484. My->COMMAND5[n] = NULL;
  485. }
  486. }
  487. void strupper(char *C)
  488. {
  489. if (C == NULL)
  490. {
  491. return;
  492. }
  493. while (*C)
  494. {
  495. *C = bwb_toupper(*C);
  496. C++;
  497. }
  498. }
  499. void strlower(char *C)
  500. {
  501. if (C == NULL)
  502. {
  503. return;
  504. }
  505. while (*C)
  506. {
  507. *C = bwb_tolower(*C);
  508. C++;
  509. }
  510. }
  511. /***************************************************************
  512. FUNCTION: main()
  513. DESCRIPTION: As in any C program, main() is the basic
  514. function from which the rest of the
  515. program is called. Some environments,
  516. however, provide their own main() functions
  517. (Microsoft Windows (tm) is an example).
  518. In these cases, the following code will
  519. have to be included in the initialization
  520. function that is called by the environment.
  521. ***************************************************************/
  522. void
  523. bwb_single_step( char * buffer )
  524. {
  525. bwx_DEBUG(__FUNCTION__);
  526. CleanLine(buffer);
  527. if ( buffer[0] == BasicNulChar )
  528. {
  529. /* empty -- do nothing */
  530. }
  531. else
  532. if (is_ln(buffer) == FALSE)
  533. {
  534. /* If there is no line number, then execute the line as received */
  535. /* RUN */
  536. bwb_Warning_Clear();
  537. SetOnError(0);
  538. bwb_xtxtline(buffer);
  539. }
  540. else
  541. if (is_numconst(buffer) == TRUE)
  542. {
  543. /*-----------------------------------------------------------------*/
  544. /* Another possibility: if buffer is a numeric constant, */
  545. /* then delete the indicated line number (JBV) */
  546. /*-----------------------------------------------------------------*/
  547. /* DELETE ... */
  548. int LineNumber;
  549. LineNumber = atoi(buffer);
  550. bwb_Warning_Clear();
  551. SetOnError(0);
  552. sprintf(buffer, "delete %d", LineNumber);
  553. bwb_xtxtline(buffer);
  554. }
  555. else
  556. {
  557. /* If there is a line number, then add it to the BASIC program */
  558. /* 100 REM */
  559. bwb_ladd(buffer, &My->bwb_start);
  560. }
  561. while( My->stack_head != NULL )
  562. {
  563. bwb_execline();
  564. }
  565. }
  566. static void execute_profile( char * FileName /*, int IsRequired */ )
  567. {
  568. FILE *profile;
  569. My->NextValidLineNumber = BasicLineNumberMin;
  570. profile = fopen( FileName, "r" );
  571. if ( profile == NULL )
  572. {
  573. /* NOT FOUND */
  574. /* OPTIONAL */
  575. return;
  576. }
  577. /* FOUND */
  578. if (My->IsInteractive)
  579. {
  580. /* set a buffer for jump: program execution returns to this point in
  581. * case of a jump (error, interrupt, or finish program) */
  582. My->program_run = 0;
  583. signal(SIGINT, break_mes);
  584. setjmp(My->mark);
  585. if (My->program_run > 0)
  586. {
  587. /* error in PROFILE */
  588. exit( 1 );
  589. }
  590. My->program_run++;
  591. }
  592. /*
  593. The profile only exists to allow
  594. setting the BWB... variables
  595. and executing OPTION ... commands
  596. No other use is supported.
  597. */
  598. {
  599. int Loop;
  600. Loop = TRUE;
  601. if (feof(profile))
  602. {
  603. Loop = FALSE;
  604. }
  605. while (Loop == TRUE)
  606. {
  607. My->read_line[0] = BasicNulChar;
  608. fgets(My->read_line, BasicStringLengthMax, profile);
  609. /* be sure that this is not EOF with a NULL line */
  610. if (feof(profile))
  611. {
  612. Loop = FALSE;
  613. }
  614. else
  615. {
  616. bwb_single_step(My->read_line);
  617. }
  618. }
  619. fclose( profile ); /* profile != NULL */
  620. profile = NULL;
  621. }
  622. }
  623. static void mark_preset_variables( void )
  624. {
  625. /* mark all existing variables as preset */
  626. /* this includes the BWB.* variables and all variables declared in any PROFILE */
  627. VariableType *v;
  628. for (v = My->var_head; v != NULL; v = v->next)
  629. {
  630. v->VariableFlags |= VARIABLE_PRESET;
  631. v->VariableFlags |= VARIABLE_COMMON;
  632. }
  633. }
  634. static void execute_program( char * FileName )
  635. {
  636. My->NextValidLineNumber = BasicLineNumberMin;
  637. My->IsCommandLineFile = TRUE;
  638. if( bwb_fload( FileName ) == FALSE )
  639. {
  640. sprintf(My->bwb_ebuf, "Failed to open file %s\n", FileName); fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  641. /* the file load has failed, so do NOT run the program */
  642. exit(1);
  643. }
  644. if (My->err_number < 0 /* file load failed */ )
  645. {
  646. /* the file load has failed, so do NOT run the program */
  647. exit(1);
  648. }
  649. bwb_RUN(&My->bwb_start);
  650. }
  651. int
  652. main(int argc, char **argv)
  653. {
  654. int i;
  655. My = calloc( 1, sizeof( GlobalType ) );
  656. if( My == NULL )
  657. {
  658. puts( "My == NULL" );
  659. return 1;
  660. }
  661. My->CurrentVersion = &bwb_vertable[ 0 ];
  662. My->IsInteractive = TRUE;
  663. My->OptionSleepValue = 1;
  664. My->OptionIndentValue = 2;
  665. My->OptionTerminalType = C_OPTION_TERMINAL_NONE;
  666. My->OptionRoundType = C_OPTION_ROUND_BANK;
  667. My->NextValidLineNumber = BasicLineNumberMin;
  668. My->IncludeLevel = 0; /* %INCLUDE */
  669. bwx_DEBUG(__FUNCTION__);
  670. bwb_init();
  671. if (My->err_number < 0 /* bwb_init() failed */ )
  672. {
  673. /* FATAL */
  674. return 1;
  675. }
  676. /* Signon message banner */
  677. if (argc < 2)
  678. {
  679. /* no parameters */
  680. if (My->IsInteractive)
  681. {
  682. bwx_signon();
  683. }
  684. else
  685. {
  686. /* if INTERACTIVE is FALSE, then we must have a program file */
  687. fputs( "Program file not specified\n", My->SYSOUT->cfp );
  688. return 1;
  689. }
  690. }
  691. /* initialize preset variables */
  692. if (My->IsInteractive)
  693. {
  694. /* set a buffer for jump: program execution returns to this point in
  695. * case of a jump (error, interrupt, or finish program) */
  696. My->program_run = 0;
  697. signal(SIGINT, break_mes);
  698. setjmp(My->mark);
  699. if (My->program_run > 0)
  700. {
  701. /* error in profile */
  702. return 1;
  703. }
  704. My->program_run++;
  705. }
  706. sprintf( My->read_line, "LET %s = \"%s\"", DEFVNAME_EDITOR, DEF_EDITOR );
  707. bwb_single_step(My->read_line);
  708. sprintf( My->read_line, "LET %s = \"%s\"", DEFVNAME_FILES, DEF_FILES );
  709. bwb_single_step(My->read_line);
  710. sprintf( My->read_line, "LET %s = \"%s\"", DEFVNAME_IMPL, IMP_IDSTRING );
  711. bwb_single_step(My->read_line);
  712. sprintf( My->read_line, "LET %s = \"%s\"", DEFVNAME_PROMPT, PROMPT );
  713. bwb_single_step(My->read_line);
  714. sprintf( My->read_line, "LET %s = \"%s\"", DEFVNAME_RENUM, DEF_RENUM );
  715. bwb_single_step(My->read_line);
  716. sprintf( My->read_line, "LET %s = %d", DEFVNAME_COLORS, DEF_COLORS );
  717. bwb_single_step(My->read_line);
  718. /* check to see if there is a program file: but do this only the first time around! */
  719. #if PROFILE
  720. execute_profile( PROFILENAME );
  721. #endif
  722. for( i = 1; i < argc; i++ )
  723. {
  724. /*
  725. SYNTAX: bwbasic
  726. SYNTAX: bwbasic --tape TapefileName.txt
  727. SYNTAX: bwbasic --profile ProfileName.txt
  728. SYNTAX: bwbasic program.bas
  729. SYNTAX: bwbasic --tape tapefile.inp --profile profile.bas program.bas
  730. */
  731. if( bwb_stricmp( argv[i], "--tape" ) == 0
  732. || bwb_stricmp( argv[i], "-t" ) == 0
  733. || bwb_stricmp( argv[i], "/tape" ) == 0
  734. || bwb_stricmp( argv[i], "/t" ) == 0
  735. )
  736. {
  737. i++;
  738. if( i < argc )
  739. {
  740. /* --tape filename */
  741. My->ExternalInputFile = fopen(argv[i], "r");
  742. }
  743. }
  744. else
  745. if( bwb_stricmp( argv[i], "--profile" ) == 0
  746. || bwb_stricmp( argv[i], "-p" ) == 0
  747. || bwb_stricmp( argv[i], "/profile" ) == 0
  748. || bwb_stricmp( argv[i], "/p" ) == 0
  749. )
  750. {
  751. i++;
  752. if( i < argc )
  753. {
  754. /* --profile filename */
  755. execute_profile( argv[i] );
  756. }
  757. }
  758. else
  759. {
  760. /* program */
  761. mark_preset_variables();
  762. {
  763. int j = i;
  764. int n = 0;
  765. for( n = 0; n < 10 && j < argc; n++, j++ )
  766. {
  767. My->COMMAND5[n] = argv[j];
  768. }
  769. }
  770. execute_program( argv[i] );
  771. break;
  772. }
  773. }
  774. if (My->IsInteractive)
  775. {
  776. /* set a buffer for jump: program execution returns to this point in
  777. * case of a jump (error, interrupt, or finish program) */
  778. My->program_run = 0;
  779. signal(SIGINT, break_mes);
  780. setjmp(My->mark);
  781. if (My->program_run > 0)
  782. {
  783. /* error in console mode */
  784. }
  785. My->program_run++;
  786. }
  787. /* main program loop */
  788. My->NextValidLineNumber = BasicLineNumberMin;
  789. mark_preset_variables();
  790. while (!feof(My->SYSIN->cfp)) /* condition !feof( My->SYSIN->cfp ) added in v1.11 */
  791. {
  792. bwb_mainloop();
  793. }
  794. bwx_terminate(); /* allow ^D (Unix) exit with grace */
  795. return 0;
  796. }
  797. /***************************************************************
  798. FUNCTION: bwb_interact()
  799. DESCRIPTION: This function gets a line from the user
  800. and processes it.
  801. ***************************************************************/
  802. int
  803. bwb_interact(void)
  804. {
  805. char LineExists = ' ';
  806. char prompt[BasicStringLengthMax + 1];
  807. bwx_DEBUG(__FUNCTION__);
  808. /* take input from keyboard */
  809. if( My->AutomaticLineNumber > 0 && My->AutomaticLineIncrement > 0 )
  810. {
  811. /* AUTO 100, 10 */
  812. LineType * l;
  813. for (l = &My->bwb_start; l != &My->bwb_end; l = l->next)
  814. {
  815. if( l->number == My->AutomaticLineNumber )
  816. {
  817. /* FOUND */
  818. LineExists = '*';
  819. break;
  820. }
  821. else
  822. if( l->number > My->AutomaticLineNumber )
  823. {
  824. /* NOT FOUND */
  825. LineExists = ' ';
  826. break;
  827. }
  828. }
  829. sprintf(prompt,"%d%c", My->AutomaticLineNumber, LineExists );
  830. }
  831. else
  832. {
  833. VariableType *v;
  834. if( (v = var_find(DEFVNAME_PROMPT,0,FALSE)) == NULL )
  835. {
  836. bwb_strcpy(prompt, PROMPT);
  837. }
  838. else
  839. {
  840. VariantType variant;
  841. if( var_get( v, &variant ) == FALSE )
  842. {
  843. bwb_strcpy(prompt, PROMPT);
  844. }
  845. else
  846. {
  847. if( variant.TypeChar == '$' )
  848. {
  849. bwb_strcpy( prompt, variant.Buffer );
  850. RELEASE( (&variant) );
  851. }
  852. else
  853. {
  854. bwb_strcpy(prompt, PROMPT);
  855. }
  856. }
  857. }
  858. }
  859. bwx_input(prompt, My->read_line);
  860. CleanLine(My->read_line); /* JBV */
  861. My->NextValidLineNumber = BasicLineNumberMin;
  862. if( My->AutomaticLineNumber > 0 && My->AutomaticLineIncrement > 0 )
  863. {
  864. if( My->read_line[0] != BasicNulChar )
  865. {
  866. /* non-empty response */
  867. if( bwb_stricmp( My->read_line, "MAN" ) == 0 )
  868. {
  869. /* MAN terminates AUTO mode */
  870. My->AutomaticLineNumber = 0;
  871. My->AutomaticLineIncrement = 0;
  872. }
  873. else
  874. {
  875. /* overwrite any existing line */
  876. char tbuf[BasicStringLengthMax + 1];
  877. sprintf(tbuf,"%d ", My->AutomaticLineNumber );
  878. bwb_strcat( tbuf, My->read_line );
  879. bwb_ladd(tbuf, &My->bwb_start);
  880. My->AutomaticLineNumber += My->AutomaticLineIncrement;
  881. }
  882. }
  883. else
  884. {
  885. /* empty response */
  886. if( LineExists == '*' )
  887. {
  888. /*
  889. An empty response with an existing line,
  890. causes AUTO to continue with the next line,
  891. leaving the current line intact.
  892. */
  893. My->AutomaticLineNumber += My->AutomaticLineIncrement;
  894. }
  895. else
  896. {
  897. /*
  898. An empty response with a non-existing line,
  899. causes AUTO to terminate.
  900. */
  901. My->AutomaticLineNumber = 0;
  902. My->AutomaticLineIncrement = 0;
  903. }
  904. }
  905. }
  906. else
  907. if (is_ln(My->read_line) == FALSE)
  908. {
  909. /* If there is no line number, execute the line as received */
  910. /* RUN */
  911. bwb_Warning_Clear();
  912. SetOnError(0);
  913. bwb_xtxtline(My->read_line);
  914. }
  915. else
  916. if (is_numconst(My->read_line) == TRUE)
  917. {
  918. /*-----------------------------------------------------------------*/
  919. /* Another possibility: if My->read_line is a numeric constant,
  920. * delete */
  921. /* the indicated line number (JBV) */
  922. /*-----------------------------------------------------------------*/
  923. /* DELETE ... */
  924. int LineNumber;
  925. LineNumber = atoi(My->read_line);
  926. bwb_Warning_Clear();
  927. SetOnError(0);
  928. sprintf(My->read_line, "delete %d", LineNumber);
  929. bwb_xtxtline(My->read_line);
  930. }
  931. else
  932. {
  933. /* If there is a line number, add the line to the file in memory */
  934. bwb_ladd(My->read_line, &My->bwb_start);
  935. }
  936. return TRUE;
  937. }
  938. /***************************************************************
  939. FUNCTION: bwb_fload()
  940. DESCRIPTION: This function loads a BASIC program
  941. file into memory given a FILE pointer.
  942. ***************************************************************/
  943. static void FixQuotes( char * buffer )
  944. {
  945. /* fix unbalanced quotes */
  946. /* 'buffer' shall be declared "char buffer[BasicStringLengthMax + 1]". */
  947. int p;
  948. int QuoteCount = 0;
  949. p = 0;
  950. while( buffer[p] != BasicNulChar )
  951. {
  952. if( buffer[p] == BasicQuoteChar )
  953. {
  954. QuoteCount++;
  955. }
  956. p++;
  957. if( p > BasicStringLengthMax )
  958. {
  959. p = BasicStringLengthMax;
  960. buffer[p] = BasicNulChar;
  961. }
  962. }
  963. if( QuoteCount & 1 )
  964. {
  965. /* odd == missing trailing quote */
  966. if( p > BasicStringLengthMax )
  967. {
  968. p = BasicStringLengthMax;
  969. }
  970. buffer[p] = BasicQuoteChar;
  971. p++;
  972. buffer[p] = BasicNulChar;
  973. }
  974. }
  975. extern int bwb_fload ( char * FileName )
  976. {
  977. FILE * file = NULL;
  978. int Loop;
  979. bwx_DEBUG(__FUNCTION__);
  980. /*
  981. Just in case you are wondering...
  982. Although this handles the most common cases, it does not handle all possible cases.
  983. The correct solution is to provide the actual filename (with extension),
  984. as it exists in the operating system.
  985. */
  986. file = NULL;
  987. if( FileName == NULL /* My->progfile */ )
  988. {
  989. /* the FileName is already in My->progfile */
  990. if (My->progfile[0] == BasicNulChar)
  991. {
  992. return FALSE;
  993. }
  994. if (file == NULL)
  995. {
  996. /* AS-IS */
  997. file = fopen(My->progfile, "r");
  998. }
  999. if (file == NULL)
  1000. {
  1001. /* UPPERCASE */
  1002. strupper(My->progfile);
  1003. file = fopen(My->progfile, "r");
  1004. }
  1005. if (file == NULL)
  1006. {
  1007. /* LOWERCASE */
  1008. strlower(My->progfile);
  1009. file = fopen(My->progfile, "r");
  1010. }
  1011. /* do NOT add extensions to existing filenames */
  1012. if (file == NULL)
  1013. {
  1014. /* NOT FOUND */
  1015. return FALSE;
  1016. }
  1017. }
  1018. else
  1019. {
  1020. if (FileName[0] == BasicNulChar)
  1021. {
  1022. return FALSE;
  1023. }
  1024. if( My->IncludeLevel > 0 )
  1025. {
  1026. /* %INCLUDE filename */
  1027. if (file == NULL)
  1028. {
  1029. /* AS-IS */
  1030. file = fopen( FileName, "r");
  1031. }
  1032. if (file == NULL)
  1033. {
  1034. /* UPPERCASE */
  1035. strupper(FileName);
  1036. file = fopen( FileName, "r");
  1037. }
  1038. if (file == NULL)
  1039. {
  1040. /* LOWERCASE */
  1041. strlower(FileName);
  1042. file = fopen( FileName, "r");
  1043. }
  1044. /* do NOT add extensions to %INCLUDE filenames */
  1045. }
  1046. else
  1047. {
  1048. if (file == NULL)
  1049. {
  1050. /* AS-IS */
  1051. bwb_strcpy(My->progfile, FileName);
  1052. file = fopen(My->progfile, "r");
  1053. }
  1054. if (file == NULL)
  1055. {
  1056. /* UPPERCASE */
  1057. bwb_strcpy(My->progfile, FileName);
  1058. strupper(My->progfile);
  1059. file = fopen(My->progfile, "r");
  1060. }
  1061. if (file == NULL)
  1062. {
  1063. /* LOWERCASE */
  1064. bwb_strcpy(My->progfile, FileName);
  1065. strlower(My->progfile);
  1066. file = fopen(My->progfile, "r");
  1067. }
  1068. if (file == NULL)
  1069. {
  1070. /* UPPERCASE + EXTENSION */
  1071. bwb_strcpy(My->progfile, FileName);
  1072. bwb_strcat(My->progfile, ".BAS");
  1073. strupper(My->progfile);
  1074. file = fopen(My->progfile, "r");
  1075. }
  1076. if (file == NULL)
  1077. {
  1078. /* LOWERCASE + EXTENSION */
  1079. bwb_strcpy(My->progfile, FileName);
  1080. bwb_strcat(My->progfile, ".bas");
  1081. strlower(My->progfile);
  1082. file = fopen(My->progfile, "r");
  1083. }
  1084. }
  1085. if (file == NULL)
  1086. {
  1087. /* NOT FOUND */
  1088. return FALSE;
  1089. }
  1090. }
  1091. My->NextValidLineNumber = BasicLineNumberMin;
  1092. Loop = TRUE;
  1093. if (feof(file))
  1094. {
  1095. Loop = FALSE;
  1096. }
  1097. while (Loop == TRUE)
  1098. {
  1099. My->read_line[0] = BasicNulChar;
  1100. fgets(My->read_line, BasicStringLengthMax, file);
  1101. if (file == My->SYSIN->cfp)
  1102. {
  1103. ResetConsoleColumn();
  1104. }
  1105. /* be sure that this is not EOF with a NULL line */
  1106. if (feof(file))
  1107. {
  1108. Loop = FALSE;
  1109. }
  1110. else
  1111. {
  1112. CleanLine(My->read_line);
  1113. if ( My->read_line[0] != BasicNulChar )
  1114. {
  1115. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
  1116. {
  1117. /* SYNTAX: %INCLUDE literal.file.name */
  1118. const char Magic_Word[] = "%INCLUDE";
  1119. int Magic_Length = bwb_strlen( Magic_Word );
  1120. if( bwb_strnicmp( My->read_line, Magic_Word, Magic_Length ) == 0 )
  1121. {
  1122. int Result;
  1123. int p = Magic_Length;
  1124. char varname[ BasicNameLengthMax + 1 ];
  1125. if( buff_read_varname( My->read_line, &p, varname ) == FALSE )
  1126. {
  1127. fputs( "Did not find filename after %INCLUDE\n", My->SYSOUT->cfp );
  1128. fputs( My->read_line, My->SYSOUT->cfp );
  1129. return FALSE;
  1130. }
  1131. if( buff_is_eol( My->read_line, &p ) == FALSE )
  1132. {
  1133. fputs( "Found garbage after %INCLUDE\n", My->SYSOUT->cfp );
  1134. fputs( My->read_line, My->SYSOUT->cfp );
  1135. return FALSE;
  1136. }
  1137. My->IncludeLevel++; /* %INCLUDE */
  1138. Result = bwb_fload( varname );
  1139. My->IncludeLevel--; /* %INCLUDE */
  1140. if( Result == FALSE )
  1141. {
  1142. fputs( "Failed to load file\n", My->SYSOUT->cfp );
  1143. fputs( My->read_line, My->SYSOUT->cfp );
  1144. return FALSE;
  1145. }
  1146. }
  1147. else
  1148. {
  1149. bwb_ladd(My->read_line, &My->bwb_start);
  1150. }
  1151. }
  1152. else
  1153. {
  1154. bwb_ladd(My->read_line, &My->bwb_start);
  1155. }
  1156. }
  1157. }
  1158. }
  1159. /* close file stream */
  1160. fclose(file); /* file != NULL */
  1161. My->NextValidLineNumber = BasicLineNumberMin;
  1162. return TRUE;
  1163. }
  1164. static char * FindClassicStatementEnd(char *C)
  1165. {
  1166. /*
  1167. * find the end of the current statement
  1168. */
  1169. bwx_DEBUG(__FUNCTION__);
  1170. if( My->CurrentVersion->OptionStatementChar == BasicNulChar && My->CurrentVersion->OptionCommentChar == BasicNulChar )
  1171. {
  1172. /* DO NOTHING: Multi-statment lines are not possible */
  1173. return NULL;
  1174. }
  1175. /* skip line number */
  1176. while (bwb_isdigit(*C))
  1177. {
  1178. C++;
  1179. }
  1180. /* skip spaces */
  1181. while (*C == ' ')
  1182. {
  1183. C++;
  1184. }
  1185. if( IS_CHAR( *C, My->CurrentVersion->OptionCommentChar ) )
  1186. {
  1187. /* The entire line is a comment */
  1188. return NULL;
  1189. }
  1190. if (bwb_strnicmp(C, "REM", 3) == 0)
  1191. {
  1192. /* The entire line is a comment */
  1193. return NULL;
  1194. }
  1195. if( (My->CurrentVersion->OptionFlags & OPTION_LABELS_ON) && (My->CurrentVersion->OptionStatementChar != BasicNulChar) )
  1196. {
  1197. /* determine if this line is a LABEL */
  1198. int p;
  1199. char label[BasicNameLengthMax + 1];
  1200. p = 0;
  1201. if( buff_read_label( C, &p, label ) )
  1202. {
  1203. buff_skip_spaces( C, &p );
  1204. if( buff_skip_char( C, &p, My->CurrentVersion->OptionStatementChar ) )
  1205. {
  1206. if( buff_is_eol( C, &p ) )
  1207. {
  1208. /* The entire line is a label */
  1209. /* LABEL : \0 */
  1210. return NULL;
  1211. }
  1212. }
  1213. }
  1214. }
  1215. /* not a special case, so split on the first unquoted OptionCommentChar or OptionStatementChar */
  1216. while (*C != BasicNulChar)
  1217. {
  1218. if (*C == BasicQuoteChar)
  1219. {
  1220. /* skip leading quote */
  1221. C++;
  1222. while (*C != BasicQuoteChar && *C != BasicNulChar)
  1223. {
  1224. /* skip string constant */
  1225. C++;
  1226. }
  1227. if (*C == BasicQuoteChar)
  1228. {
  1229. /* skip trailing quote */
  1230. C++;
  1231. }
  1232. }
  1233. else
  1234. if ( IS_CHAR( *C, My->CurrentVersion->OptionCommentChar ) /* ', ! */ )
  1235. {
  1236. /* FOUND */
  1237. return C;
  1238. }
  1239. else
  1240. if ( IS_CHAR( *C, My->CurrentVersion->OptionStatementChar ) /* :, \ */ )
  1241. {
  1242. /* FOUND */
  1243. return C;
  1244. }
  1245. else
  1246. {
  1247. C++;
  1248. }
  1249. }
  1250. /* NOT FOUND */
  1251. return NULL;
  1252. }
  1253. static void ImportClassicIfThenElse(char *InBuffer)
  1254. {
  1255. /*
  1256. **
  1257. ** Determine the type of IF command:
  1258. **
  1259. ** a) STANDARD:
  1260. ** IF x THEN line ELSE line
  1261. **
  1262. ** b) CLASSIC:
  1263. ** IF x THEN stmt(s) ELSE stmt(s)
  1264. **
  1265. ** c) STRUCTURED:
  1266. ** IF x THEN
  1267. ** stmts
  1268. ** ELSE
  1269. ** stmts
  1270. ** END IF
  1271. **
  1272. ** The STANDARD and STRUCTURED forms
  1273. ** are natively supported.
  1274. **
  1275. ** The CLASSIC form is converted to
  1276. ** the STRUCTURED form.
  1277. **
  1278. */
  1279. #define NULLCHAR BasicNulChar
  1280. #define QUOTECHAR BasicQuoteChar
  1281. #define COLONCHAR My->CurrentVersion->OptionStatementChar
  1282. #define SPACECHAR ' '
  1283. int i;
  1284. int nIF = 0;
  1285. int nTHEN = 0;
  1286. int nELSE = 0;
  1287. int nENDIF = 0;
  1288. #define NO_COMMAND 0
  1289. #define IF_COMMAND 1
  1290. #define THEN_COMMAND 2
  1291. #define ELSE_COMMAND 3
  1292. #define ENDIF_COMMAND 4
  1293. int LastCommand = NO_COMMAND;
  1294. char REM[] = "REM ";
  1295. char IF[] = "IF ";
  1296. char THEN[] = "THEN ";
  1297. char THEN2[] = "THEN";
  1298. char ELSE[] = "ELSE ";
  1299. char ENDIF[] = "END IF";
  1300. char GOTO[] = "GOTO ";
  1301. char DATA[] = "DATA ";
  1302. char CASE[] = "CASE ";
  1303. char OutBuffer[BasicStringLengthMax + 1];
  1304. char *Input = InBuffer;
  1305. char *Output = OutBuffer;
  1306. char LastChar = COLONCHAR;
  1307. int REM_len = bwb_strlen(REM);
  1308. int IF_len = bwb_strlen(IF);
  1309. int THEN_len = bwb_strlen(THEN);
  1310. int THEN2_len = bwb_strlen(THEN2);
  1311. int ELSE_len = bwb_strlen(ELSE);
  1312. int ENDIF_len = bwb_strlen(ENDIF);
  1313. int GOTO_len = bwb_strlen(GOTO);
  1314. int DATA_len = bwb_strlen(DATA);
  1315. int CASE_len = bwb_strlen(CASE);
  1316. #define OUTPUTCHAR( c ) { *Output = c; Output++; }
  1317. #define COPYCHAR { LastChar = *Input; *Output = *Input; Output++; Input++; }
  1318. #define COPY_LINENUMBER while( bwb_isdigit( *Input ) ) COPYCHAR;
  1319. #define COPY_SPACES while( *Input == SPACECHAR ) COPYCHAR;
  1320. #define COPY_IF for( i = 0; i < IF_len; i++ ) COPYCHAR;
  1321. #define COPY_THEN for( i = 0; i < THEN_len; i++ ) COPYCHAR;
  1322. #define COPY_THEN2 for( i = 0; i < THEN2_len; i++ ) COPYCHAR;
  1323. #define COPY_ELSE for( i = 0; i < ELSE_len; i++ ) COPYCHAR;
  1324. #define COPY_ENDIF for( i = 0; i < ENDIF_len; i++ ) COPYCHAR;
  1325. #define FORCE_ENDIF for( i = 0; i < ENDIF_len; i++ ) OUTPUTCHAR( ENDIF[ i ] );
  1326. #define FORCE_GOTO for( i = 0; i < GOTO_len; i++ ) OUTPUTCHAR( GOTO[ i ] );
  1327. #define FORCE_COLON if( LastChar != COLONCHAR ) OUTPUTCHAR( COLONCHAR );
  1328. bwx_DEBUG(__FUNCTION__);
  1329. if( My->CurrentVersion->OptionStatementChar == BasicNulChar )
  1330. {
  1331. /* DO NOTHING: All IFs must be STANDARD or STRUCTURED */
  1332. return;
  1333. }
  1334. COPY_LINENUMBER;
  1335. COPY_SPACES;
  1336. LastChar = COLONCHAR;
  1337. while (*Input != NULLCHAR)
  1338. {
  1339. if (*Input == My->CurrentVersion->OptionCommentChar)
  1340. {
  1341. /* comment */
  1342. break;
  1343. }
  1344. else
  1345. if (*Input == QUOTECHAR)
  1346. {
  1347. /* string constant */
  1348. COPYCHAR;
  1349. while (*Input != QUOTECHAR && *Input != NULLCHAR)
  1350. {
  1351. COPYCHAR;
  1352. }
  1353. if (*Input == QUOTECHAR)
  1354. {
  1355. COPYCHAR;
  1356. }
  1357. COPY_SPACES;
  1358. }
  1359. else
  1360. if (bwb_isalnum(LastChar))
  1361. {
  1362. /* can NOT be the start of a command */
  1363. COPYCHAR;
  1364. }
  1365. else
  1366. if (!bwb_isalpha(*Input))
  1367. {
  1368. /* can NOT be the start of a command */
  1369. COPYCHAR;
  1370. }
  1371. else
  1372. if (bwb_strnicmp(Input, REM, REM_len) == 0)
  1373. {
  1374. break;
  1375. }
  1376. else
  1377. if (bwb_strnicmp(Input, DATA, DATA_len) == 0)
  1378. {
  1379. /* DATA ... */
  1380. break;
  1381. }
  1382. else
  1383. if (bwb_strnicmp(Input, CASE, CASE_len) == 0)
  1384. {
  1385. /* CASE ... */
  1386. break;
  1387. }
  1388. else
  1389. if (bwb_strnicmp(Input, IF, IF_len) == 0)
  1390. {
  1391. /* IF */
  1392. LastCommand = IF_COMMAND;
  1393. nIF++;
  1394. COPY_IF;
  1395. COPY_SPACES;
  1396. }
  1397. else
  1398. if (bwb_strnicmp(Input, GOTO, GOTO_len) == 0 && nIF > nTHEN)
  1399. {
  1400. /* I F
  1401. *
  1402. * x GO T O
  1403. *
  1404. * li n e
  1405. *
  1406. * EL S E
  1407. *
  1408. * li n e */
  1409. LastCommand = THEN_COMMAND;
  1410. nTHEN++;
  1411. COPY_THEN;
  1412. COPY_SPACES;
  1413. COPY_LINENUMBER;
  1414. COPY_SPACES;
  1415. if (bwb_strnicmp(Input, ELSE, ELSE_len) == 0)
  1416. {
  1417. /* E L S E
  1418. *
  1419. * Li n e N u m b e r */
  1420. COPY_ELSE;
  1421. COPY_SPACES;
  1422. COPY_LINENUMBER;
  1423. COPY_SPACES;
  1424. }
  1425. /* I S
  1426. *
  1427. * ST A N D A R D ,
  1428. *
  1429. * NO T
  1430. *
  1431. * CL A S S I C */
  1432. nENDIF++;
  1433. LastCommand = ENDIF_COMMAND;
  1434. }
  1435. else
  1436. if (bwb_strnicmp(Input, THEN, THEN_len) == 0)
  1437. {
  1438. /* T H E N */
  1439. LastCommand = THEN_COMMAND;
  1440. nTHEN++;
  1441. COPY_THEN;
  1442. COPY_SPACES;
  1443. if (bwb_isdigit(*Input))
  1444. {
  1445. /* *
  1446. *
  1447. * a * )
  1448. *
  1449. * ST A N D A R D : *
  1450. *
  1451. * IF
  1452. * x TH E N
  1453. *
  1454. * li n e
  1455. *
  1456. * EL S E
  1457. *
  1458. * li n e *
  1459. *
  1460. *
  1461. */
  1462. char *SavedInput;
  1463. char *SavedOutput;
  1464. SavedInput = Input;
  1465. SavedOutput = Output;
  1466. COPY_LINENUMBER;
  1467. COPY_SPACES;
  1468. if (bwb_strnicmp(Input, ELSE, ELSE_len) == 0)
  1469. {
  1470. /* E L S E
  1471. *
  1472. * Li n e N u m b e r */
  1473. COPY_ELSE;
  1474. COPY_SPACES;
  1475. if (bwb_isdigit(*Input))
  1476. {
  1477. COPY_LINENUMBER;
  1478. COPY_SPACES;
  1479. /* I S
  1480. *
  1481. * ST A N D A R D ,
  1482. *
  1483. * NO T
  1484. *
  1485. * CL A S S I C */
  1486. nENDIF++;
  1487. LastCommand = ENDIF_COMMAND;
  1488. }
  1489. else
  1490. {
  1491. /* I F
  1492. *
  1493. * x TH E N
  1494. *
  1495. * li n e
  1496. *
  1497. * EL S E
  1498. *
  1499. * st m t s */
  1500. Input = SavedInput;
  1501. Output = SavedOutput;
  1502. FORCE_COLON;
  1503. FORCE_GOTO;
  1504. COPY_LINENUMBER;
  1505. COPY_SPACES;
  1506. }
  1507. }
  1508. else
  1509. {
  1510. /* I S
  1511. *
  1512. * ST A N D A R D ,
  1513. *
  1514. * NO T
  1515. *
  1516. * CL A S S I C */
  1517. nENDIF++;
  1518. LastCommand = ENDIF_COMMAND;
  1519. }
  1520. }
  1521. else
  1522. if (*Input == My->CurrentVersion->OptionCommentChar || *Input == NULLCHAR)
  1523. {
  1524. /* I S
  1525. *
  1526. * ST R U C T U R E D ,
  1527. *
  1528. * NO T
  1529. *
  1530. * CL A S S I C */
  1531. nENDIF++;
  1532. LastCommand = ENDIF_COMMAND;
  1533. }
  1534. else
  1535. {
  1536. /* *
  1537. *
  1538. * b * )
  1539. *
  1540. * CL A S S I C : *
  1541. *
  1542. * IF
  1543. * x TH E N
  1544. *
  1545. * st m t ( s )
  1546. *
  1547. * EL S E
  1548. *
  1549. * st m t ( s ) *
  1550. *
  1551. *
  1552. */
  1553. }
  1554. FORCE_COLON;
  1555. }
  1556. else
  1557. if (bwb_strnicmp(Input, THEN2, THEN2_len) == 0)
  1558. {
  1559. /* t r a i l i n g
  1560. *
  1561. * TH E N ? */
  1562. char *PeekInput;
  1563. PeekInput = Input;
  1564. PeekInput += THEN2_len;
  1565. while( *PeekInput == ' ' )
  1566. {
  1567. PeekInput++;
  1568. }
  1569. if (*PeekInput == My->CurrentVersion->OptionCommentChar || *PeekInput == NULLCHAR)
  1570. {
  1571. /* I S
  1572. *
  1573. * ST R U C T U R E D ,
  1574. *
  1575. * NO T
  1576. *
  1577. * CL A S S I C */
  1578. nTHEN++;
  1579. COPY_THEN2;
  1580. nENDIF++;
  1581. LastCommand = ENDIF_COMMAND;
  1582. FORCE_COLON;
  1583. }
  1584. else
  1585. {
  1586. /* T H E N x y z ,
  1587. *
  1588. * TH E N 1 2 3 */
  1589. }
  1590. }
  1591. else
  1592. if (bwb_strnicmp(Input, ELSE, ELSE_len) == 0)
  1593. {
  1594. /* E L S E */
  1595. if (LastCommand == ELSE_COMMAND)
  1596. {
  1597. /* w e
  1598. *
  1599. * ne e d
  1600. *
  1601. * an
  1602. * EN D I F
  1603. *
  1604. * he r e */
  1605. FORCE_COLON;
  1606. FORCE_ENDIF;
  1607. FORCE_COLON;
  1608. nENDIF++;
  1609. }
  1610. LastCommand = ELSE_COMMAND;
  1611. nELSE++;
  1612. FORCE_COLON;
  1613. COPY_ELSE;
  1614. FORCE_COLON;
  1615. COPY_SPACES;
  1616. if (bwb_isdigit(*Input))
  1617. {
  1618. /* I F
  1619. *
  1620. * x TH E N
  1621. *
  1622. * st m t ( s )
  1623. *
  1624. * EL S E
  1625. *
  1626. * Li n e N u m b e r */
  1627. FORCE_GOTO;
  1628. COPY_LINENUMBER;
  1629. COPY_SPACES;
  1630. }
  1631. FORCE_COLON;
  1632. }
  1633. else
  1634. if (bwb_strnicmp(Input, ENDIF, ENDIF_len) == 0)
  1635. {
  1636. /* E N D
  1637. *
  1638. * IF */
  1639. LastCommand = ENDIF_COMMAND;
  1640. nENDIF++;
  1641. COPY_ENDIF;
  1642. FORCE_COLON;
  1643. }
  1644. else
  1645. {
  1646. /* w a s
  1647. *
  1648. * NO T
  1649. *
  1650. * th e
  1651. *
  1652. * st a r t
  1653. *
  1654. * of
  1655. * a co m m a n d */
  1656. COPYCHAR;
  1657. }
  1658. }
  1659. /* end of input */
  1660. if (nENDIF < nIF)
  1661. {
  1662. while (nENDIF < nIF)
  1663. {
  1664. /* we need trailing ENDIF's */
  1665. nENDIF++;
  1666. FORCE_COLON;
  1667. FORCE_ENDIF;
  1668. }
  1669. }
  1670. /* fixup trailing REMark command */
  1671. if (bwb_strnicmp(Input, REM, REM_len) == 0)
  1672. {
  1673. /* REMark */
  1674. /* 100 A=1 REMark */
  1675. /* 100 A=1:REMark */
  1676. /* 100 A=1'REMark */
  1677. FORCE_COLON;
  1678. }
  1679. /* copy the comments */
  1680. while (*Input != NULLCHAR)
  1681. {
  1682. COPYCHAR;
  1683. /* cppcheck: (style) Variable 'LastChar' is assigned a value that is never used. */
  1684. }
  1685. OUTPUTCHAR(NULLCHAR);
  1686. bwb_strcpy(InBuffer, OutBuffer);
  1687. }
  1688. /***************************************************************
  1689. FUNCTION: bwb_ladd()
  1690. DESCRIPTION: This function adds a new line (in the
  1691. buffer) to the program in memory.
  1692. ***************************************************************/
  1693. int
  1694. bwb_ladd(char *buffer, LineType * p)
  1695. {
  1696. LineType *l;
  1697. LineType *previous;
  1698. char *newbuffer;
  1699. char *NextStatement;
  1700. char *ThisStatement;
  1701. int Replace = TRUE;
  1702. char BreakChar = BasicNulChar;
  1703. bwx_DEBUG(__FUNCTION__);
  1704. CleanLine(buffer);
  1705. if ( buffer[0] == BasicNulChar )
  1706. {
  1707. return FALSE;
  1708. }
  1709. /* AUTO-FIX UNBALANCED QUOTES */
  1710. FixQuotes(buffer);
  1711. /*
  1712. from here, the line WILL be added so the user can EDIT it,
  1713. we just complain and refuse to run if any error is detected.
  1714. */
  1715. My->rescan = TRUE; /* program needs to be scanned again */
  1716. if( IS_CHAR( *buffer, My->CurrentVersion->OptionStatementChar ) )
  1717. {
  1718. /* part of a multi-statement line */
  1719. }
  1720. else
  1721. if( IS_CHAR( *buffer, My->CurrentVersion->OptionCommentChar ) )
  1722. {
  1723. /* part of a multi-statement line */
  1724. }
  1725. else
  1726. {
  1727. ImportClassicIfThenElse(buffer);
  1728. }
  1729. ThisStatement = buffer;
  1730. NextStatement = NULL;
  1731. BreakChar = BasicNulChar;
  1732. do
  1733. {
  1734. if( BreakChar == BasicNulChar )
  1735. {
  1736. /* first pass thru the do{} while loop, do nothing */
  1737. }
  1738. else
  1739. if( IS_CHAR( BreakChar, My->CurrentVersion->OptionCommentChar ) )
  1740. {
  1741. /* ThisStatment will turn out to be the last */
  1742. *ThisStatement = My->CurrentVersion->OptionCommentChar;
  1743. }
  1744. else
  1745. if( IS_CHAR( BreakChar, My->CurrentVersion->OptionStatementChar ) )
  1746. {
  1747. /* we are NOT the last statement, skip over the OptionStatementChar */
  1748. ThisStatement++;
  1749. }
  1750. else
  1751. {
  1752. /* Internal Error */
  1753. }
  1754. if( BreakChar == BasicNulChar && IS_CHAR( *buffer, My->CurrentVersion->OptionStatementChar ) )
  1755. {
  1756. /* first pass thru and line begins with colon */
  1757. /* part of a multi-statement line */
  1758. NextStatement = NULL;
  1759. if( My->NextValidLineNumber > 1 )
  1760. {
  1761. My->NextValidLineNumber--;
  1762. }
  1763. Replace = FALSE;
  1764. }
  1765. else
  1766. if( BreakChar == BasicNulChar && IS_CHAR( *buffer, My->CurrentVersion->OptionCommentChar ) )
  1767. {
  1768. /* first pass thru and line begins with apostrophe */
  1769. /* part of a multi-statement line */
  1770. NextStatement = NULL;
  1771. if( My->NextValidLineNumber > 1 )
  1772. {
  1773. My->NextValidLineNumber--;
  1774. }
  1775. Replace = FALSE;
  1776. }
  1777. else
  1778. {
  1779. NextStatement = FindClassicStatementEnd(ThisStatement);
  1780. }
  1781. if (NextStatement == NULL)
  1782. {
  1783. /* we are the last statement */
  1784. }
  1785. else
  1786. {
  1787. /* another statement follows */
  1788. BreakChar = *NextStatement;
  1789. *NextStatement = BasicNulChar;
  1790. }
  1791. CleanLine(ThisStatement);
  1792. if ( ThisStatement[0] != BasicNulChar )
  1793. {
  1794. /* get memory for this line */
  1795. /* Revised to CALLOC pass-thru call by JBV */
  1796. if ((l = (LineType *) CALLOC((size_t) 1, sizeof(LineType), "bwb_ladd")) == NULL)
  1797. {
  1798. WARN_OUT_OF_MEMORY;
  1799. return FALSE;
  1800. }
  1801. /* this line has not been executed or numbered */
  1802. l->LineFlags = 0;
  1803. l->IncludeLevel = My->IncludeLevel; /* %INCLUDE */
  1804. /* get the first element and test for a line number */
  1805. l->position = 0;
  1806. /* set line number in line structure */
  1807. /* ALL lines will have a line number. If a line
  1808. * number is not provided, then the next available
  1809. * line number is assigned. */
  1810. newbuffer = ThisStatement;
  1811. l->number = My->NextValidLineNumber;
  1812. if( buff_read_line_number(newbuffer, &(l->position), &l->number) )
  1813. {
  1814. if (l->number < My->NextValidLineNumber)
  1815. {
  1816. /* ERROR */
  1817. sprintf(My->bwb_ebuf, "%d < %d - LINE OUT OF ORDER: %s\n", l->number, My->NextValidLineNumber, buffer);
  1818. fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  1819. My->err_number = -1; /* in bwb_ladd(), LINE OUT OF ORDER */
  1820. l->number = My->NextValidLineNumber; /* sane default */
  1821. }
  1822. else
  1823. if (l->number < BasicLineNumberMin || l->number > BasicLineNumberMax)
  1824. {
  1825. /* ERROR */
  1826. sprintf(My->bwb_ebuf, "INVALID LINE NUMBER: %s\n", buffer);
  1827. fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  1828. My->err_number = -1; /* in bwb_ladd(), INVALID LINE NUMBER */
  1829. l->number = My->NextValidLineNumber; /* sane default */
  1830. }
  1831. else
  1832. {
  1833. /* OK */
  1834. My->NextValidLineNumber = l->number;
  1835. l->LineFlags |= LINE_NUMBERED; /* line was manually numbered */
  1836. }
  1837. /* A SPACE IS REQUIRED AFTER THE LINE NUMBER
  1838. * -- NO EXCEPTIONS */
  1839. if (newbuffer[l->position] != ' ')
  1840. {
  1841. /* ERROR */
  1842. sprintf(My->bwb_ebuf, "MISSING SPACE AFTER LINE NUMBER: %s\n", buffer);
  1843. fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  1844. My->err_number = -1; /* in bwb_ladd(), MISSING SPACE AFTER LINE NUMBER */
  1845. }
  1846. /* the buffer does NOT contain the line
  1847. * number */
  1848. newbuffer += l->position;
  1849. }
  1850. /* the next valid line number is this line number plus one */
  1851. CleanLine(newbuffer);
  1852. if (*newbuffer != BasicNulChar)
  1853. {
  1854. /* not an empty line, so it must start with a
  1855. * BASIC COMMAND or VARIABLE */
  1856. if( *newbuffer == My->CurrentVersion->OptionStatementChar )
  1857. {
  1858. /* this is a multi-statement line */
  1859. newbuffer++;
  1860. while( *newbuffer == ' ' )
  1861. {
  1862. newbuffer++;
  1863. }
  1864. }
  1865. if (bwb_isalpha(*newbuffer))
  1866. {
  1867. /* OK */
  1868. }
  1869. else
  1870. if (*newbuffer == My->CurrentVersion->OptionCommentChar)
  1871. {
  1872. /* OK */
  1873. }
  1874. else
  1875. if (*newbuffer == My->CurrentVersion->OptionPrintChar)
  1876. {
  1877. /* OK */
  1878. }
  1879. else
  1880. if (*newbuffer == My->CurrentVersion->OptionImageChar)
  1881. {
  1882. /* OK */
  1883. }
  1884. else
  1885. {
  1886. /* ERROR */
  1887. sprintf(My->bwb_ebuf, "ILLEGAL CHARACTER AFTER LINE NUMBER: %s\n", newbuffer);
  1888. fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  1889. My->err_number = -1; /* in bwb_ladd(), ILLEGAL CHARACTER AFTER LINE NUMBER */
  1890. }
  1891. }
  1892. if (ln_asbuf(l, newbuffer) == FALSE)
  1893. {
  1894. /* ERROR */
  1895. sprintf(My->bwb_ebuf, "INTERNAL ERROR, ln_asbuf() == FALSE\n");
  1896. fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  1897. My->err_number = -1; /* in bwb_ladd(), INTERNAL ERROR, ln_asbuf() == FALSE */
  1898. }
  1899. if (l->cmdnum > 0)
  1900. {
  1901. /* OK */
  1902. }
  1903. else
  1904. {
  1905. /* ERROR */
  1906. sprintf(My->bwb_ebuf, "ILLEGAL COMMAND AFTER LINE NUMBER: %d %s\n", l->number, l->buffer);
  1907. fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  1908. My->err_number = -1; /* in bwb_ladd(), ILLEGAL COMMAND AFTER LINE NUMBER */
  1909. }
  1910. for (previous = p; previous != &My->bwb_end; previous = previous->next)
  1911. {
  1912. if (previous->number == l->number)
  1913. {
  1914. if (Replace == TRUE)
  1915. {
  1916. /* REPLACE 'previous' */
  1917. while (previous->number == l->number)
  1918. {
  1919. LineType * z;
  1920. z = previous;
  1921. previous = previous->next;
  1922. bwb_freeline( z );
  1923. }
  1924. l->next = previous;
  1925. p->next = l;
  1926. }
  1927. else
  1928. {
  1929. /* APPEND after 'previous' */
  1930. while (previous->next->number == l->number)
  1931. {
  1932. previous = previous->next;
  1933. }
  1934. l->next = previous->next;
  1935. previous->next = l;
  1936. }
  1937. break;
  1938. }
  1939. else
  1940. if (previous->number < l->number && l->number < previous->next->number)
  1941. {
  1942. /* INSERT BETWEEN 'previous' AND
  1943. * 'previous->next' */
  1944. l->next = previous->next;
  1945. previous->next = l;
  1946. break;
  1947. }
  1948. p = previous;
  1949. }
  1950. }
  1951. /* another statement may follow */
  1952. ThisStatement = NextStatement;
  1953. Replace = FALSE;
  1954. }
  1955. while (ThisStatement != NULL);
  1956. My->NextValidLineNumber++;
  1957. return TRUE;
  1958. }
  1959. /***************************************************************
  1960. FUNCTION: bwb_xtxtline()
  1961. DESCRIPTION: This function executes a text line, i.e.,
  1962. places it in memory and then relinquishes
  1963. control.
  1964. ***************************************************************/
  1965. LineType *
  1966. bwb_xtxtline(char *buffer)
  1967. {
  1968. bwx_DEBUG(__FUNCTION__);
  1969. /* remove old program from memory */
  1970. bwb_xnew(&My->user_line);
  1971. /* advance past whitespace */
  1972. while (*buffer == ' ')
  1973. {
  1974. buffer++;
  1975. }
  1976. if (*buffer == BasicNulChar)
  1977. {
  1978. return &My->bwb_end;
  1979. }
  1980. bwb_ladd(buffer, &My->user_line);
  1981. /* execute the line as BASIC command line */
  1982. if( bwb_incexec() )
  1983. {
  1984. My->stack_head->line = My->user_line.next; /* and set current line in it */
  1985. My->stack_head->code = EXEC_NORM;
  1986. return My->user_line.next;
  1987. }
  1988. /* ERROR */
  1989. return &My->bwb_end;
  1990. }
  1991. /***************************************************************
  1992. FUNCTION: bwb_incexec()
  1993. DESCRIPTION: This function increments the EXEC
  1994. stack counter.
  1995. ***************************************************************/
  1996. int
  1997. bwb_incexec(void)
  1998. {
  1999. StackType * stack_item;
  2000. bwx_DEBUG(__FUNCTION__);
  2001. if( My->stack_level >= EXECLEVELS )
  2002. {
  2003. WARN_OUT_OF_MEMORY;
  2004. return FALSE;
  2005. }
  2006. if ((stack_item = calloc(1, sizeof(StackType))) == NULL)
  2007. {
  2008. WARN_OUT_OF_MEMORY;
  2009. return FALSE;
  2010. }
  2011. stack_item->line = My->ThisLine;
  2012. stack_item->LoopTopLine = NULL;
  2013. stack_item->local_variable = NULL;
  2014. stack_item->OnErrorGoto = 0;
  2015. stack_item->next = My->stack_head;
  2016. My->stack_head = stack_item;
  2017. My->stack_level++;
  2018. return TRUE;
  2019. }
  2020. /***************************************************************
  2021. FUNCTION: bwb_decexec()
  2022. DESCRIPTION: This function decrements the EXEC
  2023. stack counter.
  2024. ***************************************************************/
  2025. void bwb_clrexec( void )
  2026. {
  2027. bwx_DEBUG(__FUNCTION__);
  2028. while( My->stack_head != NULL )
  2029. {
  2030. bwb_decexec();
  2031. }
  2032. }
  2033. void
  2034. bwb_decexec(void)
  2035. {
  2036. StackType * stack_item;
  2037. bwx_DEBUG(__FUNCTION__);
  2038. if( My->stack_head == NULL )
  2039. {
  2040. WARN_RETURN_WITHOUT_GOSUB;
  2041. return;
  2042. }
  2043. stack_item = My->stack_head;
  2044. My->stack_head = stack_item->next;
  2045. free( stack_item );
  2046. My->stack_level--;
  2047. }
  2048. /***************************************************************
  2049. FUNCTION: bwb_mainloop()
  2050. DESCRIPTION: This C function performs one iteration
  2051. of the interpreter. In a non-preemptive
  2052. scheduler, this function should be called
  2053. by the scheduler, not by bwBASIC code.
  2054. ***************************************************************/
  2055. void
  2056. bwb_mainloop(void)
  2057. {
  2058. bwx_DEBUG(__FUNCTION__);
  2059. if( My->stack_head != NULL )
  2060. {
  2061. /* BASIC program running */
  2062. bwb_execline(); /* execute one line of program */
  2063. return;
  2064. }
  2065. /* BASIC program completed */
  2066. if( My->ExternalInputFile != NULL )
  2067. {
  2068. /* for automated testing, TAPE command */
  2069. if( bwb_is_eof( My->ExternalInputFile ) == FALSE )
  2070. {
  2071. /* TAPE command is active */
  2072. bwb_interact(); /* get user interaction */
  2073. return;
  2074. }
  2075. }
  2076. /* TAPE command inactive or completed */
  2077. if (My->IsCommandLineFile == TRUE)
  2078. {
  2079. /* BASIC program was started from command line */
  2080. bwx_terminate();
  2081. return;
  2082. }
  2083. /* BASIC program was not started from command line */
  2084. if (My->IsInteractive)
  2085. {
  2086. /* interactive */
  2087. bwb_interact(); /* get user interaction */
  2088. return;
  2089. }
  2090. /* non-interactive */
  2091. bwx_terminate();
  2092. }
  2093. /***************************************************************
  2094. FUNCTION: bwb_execline()
  2095. DESCRIPTION: This function executes a single line of
  2096. a program in memory. This function is
  2097. called by bwb_mainloop().
  2098. ***************************************************************/
  2099. /*
  2100. ON statement (event trapping)
  2101. ON { COM(n) | KEY(n) | PEN | PLAY(n) | STRIG(n) | TIMER (x) } GOSUB line_number
  2102. ON ERROR GOTO line_number
  2103. */
  2104. #define EVENT_ERROR 0x01
  2105. #define EVENT_COM 0X02
  2106. #define EVENT_KEY 0X04
  2107. #define EVENT_PEN 0X08
  2108. #define EVENT_PLAY 0X10
  2109. #define EVENT_STRIG 0X20
  2110. #define EVENT_TIMER 0X40
  2111. #define EVENT_USER 0X80
  2112. static void SetEvent(char EventType)
  2113. {
  2114. bwx_DEBUG(__FUNCTION__);
  2115. My->EventQueue |= EventType;
  2116. }
  2117. static void ClrEvent(char EventType)
  2118. {
  2119. bwx_DEBUG(__FUNCTION__);
  2120. My->EventQueue &= ~EventType;
  2121. }
  2122. static int HasEvent(char EventType)
  2123. {
  2124. bwx_DEBUG(__FUNCTION__);
  2125. return My->EventQueue & EventType;
  2126. }
  2127. void
  2128. bwb_Timer_On(void)
  2129. {
  2130. bwx_DEBUG(__FUNCTION__);
  2131. SetEvent(EVENT_TIMER);
  2132. }
  2133. void
  2134. bwb_Timer_Off(void)
  2135. {
  2136. bwx_DEBUG(__FUNCTION__);
  2137. ClrEvent(EVENT_TIMER);
  2138. }
  2139. void
  2140. bwb_Warning( int ErrorLevel, char *ErrorMessage )
  2141. {
  2142. bwx_DEBUG(__FUNCTION__);
  2143. if( ErrorLevel == 0 )
  2144. {
  2145. /* clear any existing error */
  2146. My->err_number = 0; /* ERR */
  2147. My->err_line = NULL; /* ERL */
  2148. bwb_strcpy(My->ErrMsg, ""); /* ERROR$ */
  2149. ClrEvent(EVENT_ERROR);
  2150. }
  2151. else
  2152. {
  2153. if( HasEvent(EVENT_ERROR) == 0 ) /* no errors pending */
  2154. {
  2155. /* only keep the first pending error to occur */
  2156. if( ErrorMessage == NULL )
  2157. {
  2158. /* use the default error message */
  2159. if( ErrorLevel > 0 && ErrorLevel < 80 )
  2160. {
  2161. ErrorMessage = DefaultErrorMessage[ ErrorLevel ];
  2162. }
  2163. else
  2164. {
  2165. ErrorMessage = DefaultErrorMessage[ 0 ];
  2166. }
  2167. }
  2168. else
  2169. {
  2170. /* use a specified error message */
  2171. if( bwb_strlen(ErrorMessage) > 255 )
  2172. {
  2173. ErrorMessage[ 255 ] = BasicNulChar;
  2174. }
  2175. }
  2176. My->err_number = ErrorLevel; /* ERR */
  2177. if( My->stack_head != NULL )
  2178. {
  2179. My->err_line = My->stack_head->line; /* ERL */
  2180. }
  2181. bwb_strcpy(My->ErrMsg, ErrorMessage); /* ERROR$ */
  2182. SetEvent(EVENT_ERROR);
  2183. }
  2184. }
  2185. }
  2186. int
  2187. bwb_Warning_Pending(void)
  2188. {
  2189. bwx_DEBUG(__FUNCTION__);
  2190. return HasEvent(EVENT_ERROR);
  2191. }
  2192. void
  2193. bwb_Warning_Clear(void)
  2194. {
  2195. bwx_DEBUG(__FUNCTION__);
  2196. bwb_Warning(0, ""); /* clear */
  2197. }
  2198. int
  2199. bwb_Warning_Overflow(char *Message)
  2200. {
  2201. /* Numeric overflow, String overflow, SPC() and TAB() */
  2202. /* OVERFLOW is different. A default value can be used. */
  2203. /* If ON ERROR GOTO 0, then display message and continue (returns FALSE), otherwise ERROR 6 (returns TRUE) */
  2204. bwx_DEBUG(__FUNCTION__);
  2205. if (GetOnError() == 0)
  2206. {
  2207. /* user error handler NOT active */
  2208. #if TRUE
  2209. fputs( Message, My->SYSOUT->cfp );
  2210. fputs( "\n", My->SYSOUT->cfp );
  2211. #else
  2212. sprintf( My->bwb_ebuf, "LINE %d: %s\n", My->ThisLine->number, Message );
  2213. fputs( My->bwb_ebuf, My->SYSOUT->cfp );
  2214. #endif
  2215. return FALSE;
  2216. }
  2217. /* user error handler IS active */
  2218. bwb_Warning(6, Message); /* Overflow */
  2219. return TRUE;
  2220. }
  2221. void
  2222. bwb_execline(void)
  2223. {
  2224. LineType *r, *l;
  2225. bwx_DEBUG(__FUNCTION__);
  2226. l = My->stack_head->line;
  2227. /* if the line is &My->bwb_end, then break out of EXEC loops */
  2228. if (l == &My->bwb_end || My->err_number < 0)
  2229. {
  2230. bwb_clrexec();
  2231. return;
  2232. }
  2233. /* Check for wacko line numbers */
  2234. My->ThisLine = l;
  2235. /* Print line number if trace is on */
  2236. if (My->bwb_trace == TRUE)
  2237. {
  2238. if (l->number > 0)
  2239. {
  2240. sprintf(My->bwb_ebuf, "[ %d %s ]", l->number, l->buffer);
  2241. prn_xprintf(My->bwb_ebuf);
  2242. }
  2243. }
  2244. l->position = l->Startpos;
  2245. /* if there is a BASIC command in the line, execute it here */
  2246. if (l->cmdnum > 0)
  2247. {
  2248. /* OK */
  2249. }
  2250. else
  2251. {
  2252. WARN_ILLEGAL_DIRECT;
  2253. l->cmdnum = C_REM;
  2254. }
  2255. /* l->cmdnum > 0 */
  2256. if( l->LineFlags & LINE_BREAK )
  2257. {
  2258. /* BREAK line */
  2259. l->LineFlags &= ~LINE_BREAK;
  2260. My->ContinueLine = l;
  2261. bwx_STOP();
  2262. return;
  2263. }
  2264. /* execute the command vector */
  2265. /* advance beyond whitespace */
  2266. line_skip_spaces(l);
  2267. if (My->CurrentVersion->OptionFlags & (OPTION_COVERAGE_ON) )
  2268. {
  2269. /* * We do this here * so "END" and "STOP" * are marked */
  2270. if (l->cmdnum == C_DATA)
  2271. {
  2272. /* DATA lines are marked when they are READ */
  2273. }
  2274. else
  2275. {
  2276. /* this line was executed */
  2277. l->LineFlags |= LINE_EXECUTED;
  2278. }
  2279. }
  2280. r = bwb_vector(l);
  2281. if( r == NULL )
  2282. {
  2283. WARN_INTERNAL_ERROR;
  2284. return;
  2285. }
  2286. if (My->err_number < 0) /* in bwb_execline, FATAL ERROR PENDING */
  2287. {
  2288. /* FATAL */
  2289. bwb_clrexec();
  2290. return;
  2291. }
  2292. if( bwb_Warning_Pending() /* Keep This */ )
  2293. {
  2294. /* we are probably not at the end-of-the-line */
  2295. }
  2296. else
  2297. if (r == l)
  2298. {
  2299. /* we should be at the end-of-the-line */
  2300. if ( line_is_eol(l) )
  2301. {
  2302. /* OK */
  2303. }
  2304. else
  2305. {
  2306. WARN_SYNTAX_ERROR;
  2307. return;
  2308. }
  2309. }
  2310. else
  2311. {
  2312. /* we are probably not at the end-of-the-line */
  2313. }
  2314. if (HasEvent(EVENT_ERROR))
  2315. {
  2316. /* a NON-FATAL ERROR has occurred. ERR, ERL, and ERROR$ were
  2317. * already set using bwb_warning(ERR,ERROR$) */
  2318. int err_gotol;
  2319. ClrEvent(EVENT_ERROR);
  2320. err_gotol = GetOnError();
  2321. if (l->number == 0)
  2322. {
  2323. /* BASIC PROMPT */
  2324. /* For example: 10 ON ERROR GOTO 20 ERROR 1 */
  2325. /* fall thru to the DEFAULT ERROR HANDLER */
  2326. }
  2327. else
  2328. if (My->err_line == NULL)
  2329. {
  2330. /* BASIC PROMPT */
  2331. /* For example: 10 ON ERROR GOTO 20 ERROR 1 */
  2332. /* fall thru to the DEFAULT ERROR HANDLER */
  2333. }
  2334. else
  2335. if (My->err_line->number == 0)
  2336. {
  2337. /* BASIC PROMPT */
  2338. /* For example: 10 ON ERROR GOTO 20 ERROR 1 */
  2339. /* fall thru to the DEFAULT ERROR HANDLER */
  2340. }
  2341. else
  2342. if (err_gotol == -1)
  2343. {
  2344. /* ON ERROR RESUME NEXT */
  2345. r->next->position = 0;
  2346. My->stack_head->line = r->next;
  2347. return;
  2348. }
  2349. else
  2350. if (err_gotol == 0)
  2351. {
  2352. /* ON ERROR GOTO 0 */
  2353. /* fall thru to the DEFAULT ERROR HANDLER */
  2354. }
  2355. else
  2356. if (err_gotol == My->err_line->number)
  2357. {
  2358. /* RECURSION */
  2359. /* For example: 10 ON ERROR GOTO 20 20 ERROR 1 */
  2360. /* fall thru to the DEFAULT ERROR HANDLER */
  2361. }
  2362. else
  2363. {
  2364. /* USER ERROR HANDLER SPECIFIED */
  2365. /* find the user-specified error handler and jump there */
  2366. LineType *x;
  2367. for (x = &My->bwb_start; x != &My->bwb_end; x = x->next)
  2368. {
  2369. if (x->number == err_gotol)
  2370. {
  2371. /* FOUND */
  2372. if( My->CurrentVersion->OptionFlags & ( OPTION_ERROR_GOSUB ) )
  2373. {
  2374. /* OPTION ERROR GOSUB */
  2375. if( bwb_incexec() )
  2376. {
  2377. x->position = 0;
  2378. My->stack_head->line = x;
  2379. My->stack_head->code = EXEC_GOSUB;
  2380. }
  2381. else
  2382. {
  2383. /* ERROR */
  2384. My->stack_head->line = &My->bwb_end;
  2385. }
  2386. }
  2387. else
  2388. {
  2389. /* OPTION ERROR GOTO */
  2390. x->position = 0; /* start of line */
  2391. My->stack_head->line = x;
  2392. }
  2393. return;
  2394. }
  2395. }
  2396. /* NOT FOUND */
  2397. /* fall thru to the DEFAULT ERROR HANDLER */
  2398. }
  2399. /* DEFAULT ERROR HANDLER */
  2400. /* FATAL */
  2401. bwx_DEBUG(My->ErrMsg); /* My->MaintainerDebugOn */
  2402. prn_xprintf("\n");
  2403. if( My->CurrentVersion->OptionVersionBitmask & ( C77 ) )
  2404. {
  2405. if( My->progfile[ 0 ] != BasicNulChar )
  2406. {
  2407. prn_xprintf("FILE:");
  2408. prn_xprintf(My->progfile);
  2409. prn_xprintf(", ");
  2410. }
  2411. }
  2412. prn_xprintf("ERROR in line");
  2413. if( My->ThisLine != NULL )
  2414. {
  2415. if ( BasicLineNumberMin <= My->ThisLine->number && My->ThisLine->number <= BasicLineNumberMax )
  2416. {
  2417. /* BASIC program line */
  2418. char tbuf[32];
  2419. sprintf(tbuf, "%d", My->ThisLine->number);
  2420. prn_xprintf(" ");
  2421. prn_xprintf(tbuf);
  2422. }
  2423. }
  2424. prn_xprintf(": ");
  2425. prn_xprintf(My->ErrMsg);
  2426. prn_xprintf("\n");
  2427. if (My->CurrentVersion->OptionFlags & ( OPTION_TRACE_ON ) )
  2428. {
  2429. /*
  2430. ** Dump the BASIC stack trace when a FATAL error occurs.
  2431. ** First line is the TOP of the stack.
  2432. ** Last line is the BOTTOM of the stack.
  2433. */
  2434. StackType *stack_item;
  2435. prn_xprintf("\nSTACK TRACE:\n");
  2436. for( stack_item = My->stack_head; stack_item != NULL; stack_item = stack_item->next )
  2437. {
  2438. LineType *l;
  2439. l = stack_item->line;
  2440. if (l != NULL)
  2441. {
  2442. if ( BasicLineNumberMin <= l->number && l->number <= BasicLineNumberMax )
  2443. {
  2444. /* BASIC program line */
  2445. char LineNumber[32];
  2446. sprintf(LineNumber, "%d:", l->number);
  2447. prn_xprintf(LineNumber);
  2448. if (l->buffer != NULL)
  2449. {
  2450. prn_xprintf(l->buffer);
  2451. }
  2452. prn_xprintf("\n");
  2453. }
  2454. }
  2455. }
  2456. }
  2457. My->AutomaticLineNumber = 0;
  2458. My->AutomaticLineIncrement = 0;
  2459. if (My->IsInteractive)
  2460. {
  2461. /* INTERACTIVE: terminate program */
  2462. /* reset all stack counters */
  2463. bwb_clrexec();
  2464. SetOnError(0);
  2465. My->err_number = -1; /* in break_handler() */
  2466. /* reset the break handler */
  2467. signal(SIGINT, break_mes);
  2468. return;
  2469. }
  2470. /* NOT INTERACTIVE: terminate immediately */
  2471. bwx_terminate();
  2472. return; /* never reached */
  2473. }
  2474. if (l->number > 0)
  2475. {
  2476. /* These events only occur in running programs */
  2477. if (HasEvent(EVENT_TIMER))
  2478. {
  2479. /* TIMER ON */
  2480. if (My->tmr_count > 0)
  2481. {
  2482. if (bwx_TIMER(0) > My->tmr_expires)
  2483. {
  2484. ClrEvent(EVENT_TIMER);
  2485. if (My->tmr_line > 0)
  2486. {
  2487. /* ON TIMER( My->tmr_count ) GOSUB My->tmr_line */
  2488. LineType *x;
  2489. for (x = &My->bwb_start; x != &My->bwb_end; x = x->next)
  2490. {
  2491. if (x->number == My->tmr_line)
  2492. {
  2493. /* FOUND */
  2494. /* save current stack level */
  2495. My->stack_head->line = r;
  2496. /* increment exec stack */
  2497. if( bwb_incexec() )
  2498. {
  2499. /* set the new position to x and return x */
  2500. x->position = 0;
  2501. My->stack_head->line = x;
  2502. My->stack_head->code = EXEC_GOSUB;
  2503. }
  2504. else
  2505. {
  2506. /* ERROR */
  2507. My->stack_head->line = &My->bwb_end;
  2508. }
  2509. return;
  2510. }
  2511. }
  2512. /* NOT FOUND */
  2513. }
  2514. }
  2515. }
  2516. }
  2517. }
  2518. /* check for end of line: if so, advance to next line and return */
  2519. if (r == l)
  2520. {
  2521. /* advance to the next line */
  2522. l->next->position = 0;
  2523. r = l->next;
  2524. }
  2525. else
  2526. if ( line_is_eol( r ) )
  2527. {
  2528. /* we could be at the end-of-the-line, added for RETURN */
  2529. /* advance to the next line */
  2530. r->next->position = 0;
  2531. r = r->next;
  2532. }
  2533. /* else reset with the value in r */
  2534. My->stack_head->line = r;
  2535. }
  2536. /***************************************************************
  2537. FUNCTION: ln_asbuf()
  2538. DESCRIPTION: This function allocates memory and copies
  2539. a null-terminated string to a line buffer.
  2540. ***************************************************************/
  2541. int
  2542. ln_asbuf(LineType * l, char *s)
  2543. {
  2544. bwx_DEBUG(__FUNCTION__);
  2545. if (l->buffer != NULL)
  2546. {
  2547. /* Revised to FREE pass-thru call by JBV */
  2548. FREE(l->buffer, "ln_asbuf");
  2549. l->buffer = NULL; /* JBV */
  2550. }
  2551. /* Revised to CALLOC pass-thru call by JBV */
  2552. if ((l->buffer = CALLOC(bwb_strlen(s) + 2, sizeof(char), "ln_asbuf")) == NULL)
  2553. {
  2554. WARN_OUT_OF_MEMORY;
  2555. return FALSE;
  2556. }
  2557. /* copy the whole line to the line structure buffer */
  2558. bwb_strcpy(l->buffer, s);
  2559. /* strip CR from the buffer */
  2560. CleanLine(l->buffer);
  2561. /* determine command */
  2562. line_start(l);
  2563. return TRUE;
  2564. }
  2565. /***************************************************************
  2566. FUNCTION: is_ln()
  2567. DESCRIPTION: This function determines whether a program
  2568. line (in buffer) begins with a line number.
  2569. ***************************************************************/
  2570. int
  2571. is_ln(char *buffer)
  2572. {
  2573. int position;
  2574. bwx_DEBUG(__FUNCTION__);
  2575. position = 0;
  2576. buff_skip_spaces(buffer, &position);
  2577. if( bwb_isdigit(buffer[position]) )
  2578. {
  2579. return TRUE;
  2580. }
  2581. return FALSE;
  2582. }
  2583. /***************************************************************
  2584. FUNCTION: CALLOC()
  2585. DESCRIPTION: Pass-thru function to calloc() for debugging
  2586. purposes. Added by JBV 10/95
  2587. ***************************************************************/
  2588. void *
  2589. CALLOC(size_t nelem, size_t elsize, char *str)
  2590. {
  2591. void *ptr;
  2592. bwx_DEBUG(__FUNCTION__);
  2593. ptr = calloc(nelem, elsize);
  2594. return ptr;
  2595. }
  2596. /***************************************************************
  2597. FUNCTION: FREE()
  2598. DESCRIPTION: Pass-thru function to free() for debugging
  2599. purposes. Added by JBV 10/95
  2600. ***************************************************************/
  2601. void
  2602. FREE(void *ptr, char *str)
  2603. {
  2604. bwx_DEBUG(__FUNCTION__);
  2605. free(ptr);
  2606. }
  2607. /* SWITCH */
  2608. LineType *
  2609. bwb_vector( LineType *l )
  2610. {
  2611. LineType *r;
  2612. bwx_DEBUG(__FUNCTION__);
  2613. bwx_DEBUG( l->buffer ); /* My->MaintainerDebugOn */
  2614. switch( l->cmdnum )
  2615. {
  2616. case C_QUEST:
  2617. r = bwb_QUEST( l );
  2618. break;
  2619. case C_APPEND:
  2620. r = bwb_APPEND( l );
  2621. break;
  2622. case C_AS:
  2623. r = bwb_AS( l );
  2624. break;
  2625. case C_AUTO:
  2626. r = bwb_AUTO( l );
  2627. break;
  2628. case C_BACKSPACE:
  2629. r = bwb_BACKSPACE( l );
  2630. break;
  2631. case C_BREAK:
  2632. r = bwb_BREAK( l );
  2633. break;
  2634. case C_BYE:
  2635. r = bwb_BYE( l );
  2636. break;
  2637. case C_CALL:
  2638. r = bwb_CALL( l );
  2639. break;
  2640. case C_CASE:
  2641. r = bwb_CASE( l );
  2642. break;
  2643. case C_CASE_ELSE:
  2644. r = bwb_CASE_ELSE( l );
  2645. break;
  2646. case C_CHAIN:
  2647. r = bwb_CHAIN( l );
  2648. break;
  2649. case C_CHANGE:
  2650. r = bwb_CHANGE( l );
  2651. break;
  2652. case C_CLEAR:
  2653. r = bwb_CLEAR( l );
  2654. break;
  2655. case C_CLOAD:
  2656. r = bwb_CLOAD( l );
  2657. break;
  2658. case C_CLOAD8:
  2659. r = bwb_CLOAD8( l );
  2660. break;
  2661. case C_CLOSE:
  2662. r = bwb_CLOSE( l );
  2663. break;
  2664. case C_CLR:
  2665. r = bwb_CLR( l );
  2666. break;
  2667. case C_CMDS:
  2668. r = bwb_CMDS( l );
  2669. break;
  2670. case C_COMMON:
  2671. r = bwb_COMMON( l );
  2672. break;
  2673. case C_CONSOLE:
  2674. r = bwb_CONSOLE( l );
  2675. break;
  2676. case C_CONT:
  2677. r = bwb_CONT( l );
  2678. break;
  2679. case C_CREATE:
  2680. r = bwb_CREATE( l );
  2681. break;
  2682. case C_CSAVE:
  2683. r = bwb_CSAVE( l );
  2684. break;
  2685. case C_CSAVE8:
  2686. r = bwb_CSAVE8( l );
  2687. break;
  2688. case C_DATA:
  2689. r = bwb_DATA( l );
  2690. break;
  2691. case C_DEF:
  2692. r = bwb_DEF( l );
  2693. break;
  2694. case C_DEF_SUB:
  2695. r = bwb_DEF_SUB( l );
  2696. break;
  2697. case C_DEFBYT:
  2698. r = bwb_DEFBYT( l );
  2699. break;
  2700. case C_DEFCUR:
  2701. r = bwb_DEFCUR( l );
  2702. break;
  2703. case C_DEFDBL:
  2704. r = bwb_DEFDBL( l );
  2705. break;
  2706. case C_DEFINT:
  2707. r = bwb_DEFINT( l );
  2708. break;
  2709. case C_DEFLNG:
  2710. r = bwb_DEFLNG( l );
  2711. break;
  2712. case C_DEFSNG:
  2713. r = bwb_DEFSNG( l );
  2714. break;
  2715. case C_DEFSTR:
  2716. r = bwb_DEFSTR( l );
  2717. break;
  2718. case C_DELETE:
  2719. r = bwb_DELETE( l );
  2720. break;
  2721. case C_DELIMIT:
  2722. r = bwb_DELIMIT( l );
  2723. break;
  2724. case C_DIM:
  2725. r = bwb_DIM( l );
  2726. break;
  2727. case C_DO:
  2728. r = bwb_DO( l );
  2729. break;
  2730. case C_DSP:
  2731. r = bwb_DSP( l );
  2732. break;
  2733. case C_EDIT:
  2734. r = bwb_EDIT( l );
  2735. break;
  2736. case C_ELSE:
  2737. r = bwb_ELSE( l );
  2738. break;
  2739. case C_ELSEIF:
  2740. r = bwb_ELSEIF( l );
  2741. break;
  2742. case C_END:
  2743. r = bwb_END( l );
  2744. break;
  2745. case C_END_FUNCTION:
  2746. r = bwb_END_FUNCTION( l );
  2747. break;
  2748. case C_END_IF:
  2749. r = bwb_END_IF( l );
  2750. break;
  2751. case C_END_SELECT:
  2752. r = bwb_END_SELECT( l );
  2753. break;
  2754. case C_END_SUB:
  2755. r = bwb_END_SUB( l );
  2756. break;
  2757. case C_ERASE:
  2758. r = bwb_ERASE( l );
  2759. break;
  2760. case C_EXCHANGE:
  2761. r = bwb_EXCHANGE( l );
  2762. break;
  2763. case C_EXIT:
  2764. r = bwb_EXIT( l );
  2765. break;
  2766. case C_EXIT_DO:
  2767. r = bwb_EXIT_DO( l );
  2768. break;
  2769. case C_EXIT_FOR:
  2770. r = bwb_EXIT_FOR( l );
  2771. break;
  2772. case C_EXIT_FUNCTION:
  2773. r = bwb_EXIT_FUNCTION( l );
  2774. break;
  2775. case C_EXIT_SUB:
  2776. r = bwb_EXIT_SUB( l );
  2777. break;
  2778. case C_EXIT_UNTIL:
  2779. r = bwb_EXIT_UNTIL( l );
  2780. break;
  2781. case C_EXIT_WHILE:
  2782. r = bwb_EXIT_WHILE( l );
  2783. break;
  2784. case C_FEND:
  2785. r = bwb_FEND( l );
  2786. break;
  2787. case C_FIELD:
  2788. r = bwb_FIELD( l );
  2789. break;
  2790. case C_FILE:
  2791. r = bwb_FILE( l );
  2792. break;
  2793. case C_FILES:
  2794. r = bwb_FILES( l );
  2795. break;
  2796. case C_FNCS:
  2797. r = bwb_FNCS( l );
  2798. break;
  2799. case C_FNEND:
  2800. r = bwb_FNEND( l );
  2801. break;
  2802. case C_FOR:
  2803. r = bwb_FOR( l );
  2804. break;
  2805. case C_FUNCTION:
  2806. r = bwb_FUNCTION( l );
  2807. break;
  2808. case C_GET:
  2809. r = bwb_GET( l );
  2810. break;
  2811. case C_GO:
  2812. r = bwb_GO( l );
  2813. break;
  2814. case C_GO_SUB:
  2815. r = bwb_GO_SUB( l );
  2816. break;
  2817. case C_GO_TO:
  2818. r = bwb_GO_TO( l );
  2819. break;
  2820. case C_GOODBYE:
  2821. r = bwb_GOODBYE( l );
  2822. break;
  2823. case C_GOSUB:
  2824. r = bwb_GOSUB( l );
  2825. break;
  2826. case C_GOTO:
  2827. r = bwb_GOTO( l );
  2828. break;
  2829. case C_HELP:
  2830. r = bwb_HELP( l );
  2831. break;
  2832. case C_IF:
  2833. r = bwb_IF( l );
  2834. break;
  2835. case C_IF_END:
  2836. r = bwb_IF_END( l );
  2837. break;
  2838. case C_IF_MORE:
  2839. r = bwb_IF_MORE( l );
  2840. break;
  2841. case C_IF_THEN:
  2842. r = bwb_IF_THEN( l );
  2843. break;
  2844. case C_IMAGE:
  2845. r = bwb_IMAGE( l );
  2846. break;
  2847. case C_INPUT:
  2848. r = bwb_INPUT( l );
  2849. break;
  2850. case C_LET:
  2851. r = bwb_LET( l );
  2852. break;
  2853. case C_LINE:
  2854. r = bwb_LINE( l );
  2855. break;
  2856. case C_LIST:
  2857. r = bwb_LIST( l );
  2858. break;
  2859. case C_LLIST:
  2860. r = bwb_LLIST( l );
  2861. break;
  2862. case C_LOAD:
  2863. r = bwb_LOAD( l );
  2864. break;
  2865. case C_LOOP:
  2866. r = bwb_LOOP( l );
  2867. break;
  2868. case C_LPRINT:
  2869. r = bwb_LPRINT( l );
  2870. break;
  2871. case C_LPRINTER:
  2872. r = bwb_LPRINTER( l );
  2873. break;
  2874. case C_LSET:
  2875. r = bwb_LSET( l );
  2876. break;
  2877. case C_MAINTAINER:
  2878. r = bwb_MAINTAINER( l );
  2879. break;
  2880. case C_MARGIN:
  2881. r = bwb_MARGIN( l );
  2882. break;
  2883. case C_MAT:
  2884. r = bwb_MAT( l );
  2885. break;
  2886. case C_MAT_GET:
  2887. r = bwb_MAT_GET( l );
  2888. break;
  2889. case C_MAT_INPUT:
  2890. r = bwb_MAT_INPUT( l );
  2891. break;
  2892. case C_MAT_PRINT:
  2893. r = bwb_MAT_PRINT( l );
  2894. break;
  2895. case C_MAT_PUT:
  2896. r = bwb_MAT_PUT( l );
  2897. break;
  2898. case C_MAT_READ:
  2899. r = bwb_MAT_READ( l );
  2900. break;
  2901. case C_MAT_WRITE:
  2902. r = bwb_MAT_WRITE( l );
  2903. break;
  2904. case C_MERGE:
  2905. r = bwb_MERGE( l );
  2906. break;
  2907. case C_MID4:
  2908. r = bwb_MID4( l );
  2909. break;
  2910. case C_NAME:
  2911. r = bwb_NAME( l );
  2912. break;
  2913. case C_NEW:
  2914. r = bwb_NEW( l );
  2915. break;
  2916. case C_NEXT:
  2917. r = bwb_NEXT( l );
  2918. break;
  2919. case C_OF:
  2920. r = bwb_OF( l );
  2921. break;
  2922. case C_OLD:
  2923. r = bwb_OLD( l );
  2924. break;
  2925. case C_ON:
  2926. r = bwb_ON( l );
  2927. break;
  2928. case C_ON_ERROR:
  2929. r = bwb_ON_ERROR( l );
  2930. break;
  2931. case C_ON_ERROR_GOSUB:
  2932. r = bwb_ON_ERROR_GOSUB( l );
  2933. break;
  2934. case C_ON_ERROR_GOTO:
  2935. r = bwb_ON_ERROR_GOTO( l );
  2936. break;
  2937. case C_ON_ERROR_RESUME:
  2938. r = bwb_ON_ERROR_RESUME( l );
  2939. break;
  2940. case C_ON_ERROR_RESUME_NEXT:
  2941. r = bwb_ON_ERROR_RESUME_NEXT( l );
  2942. break;
  2943. case C_ON_ERROR_RETURN:
  2944. r = bwb_ON_ERROR_RETURN( l );
  2945. break;
  2946. case C_ON_ERROR_RETURN_NEXT:
  2947. r = bwb_ON_ERROR_RETURN_NEXT( l );
  2948. break;
  2949. case C_ON_TIMER:
  2950. r = bwb_ON_TIMER( l );
  2951. break;
  2952. case C_OPEN:
  2953. r = bwb_OPEN( l );
  2954. break;
  2955. case C_OPTION:
  2956. r = bwb_OPTION( l );
  2957. break;
  2958. case C_OPTION_ANGLE:
  2959. r = bwb_OPTION_ANGLE( l );
  2960. break;
  2961. case C_OPTION_ANGLE_DEGREES:
  2962. r = bwb_OPTION_ANGLE_DEGREES( l );
  2963. break;
  2964. case C_OPTION_ANGLE_GRADIANS:
  2965. r = bwb_OPTION_ANGLE_GRADIANS( l );
  2966. break;
  2967. case C_OPTION_ANGLE_RADIANS:
  2968. r = bwb_OPTION_ANGLE_RADIANS( l );
  2969. break;
  2970. case C_OPTION_ARITHMETIC:
  2971. r = bwb_OPTION_ARITHMETIC( l );
  2972. break;
  2973. case C_OPTION_ARITHMETIC_DECIMAL:
  2974. r = bwb_OPTION_ARITHMETIC_DECIMAL( l );
  2975. break;
  2976. case C_OPTION_ARITHMETIC_FIXED:
  2977. r = bwb_OPTION_ARITHMETIC_FIXED( l );
  2978. break;
  2979. case C_OPTION_ARITHMETIC_NATIVE:
  2980. r = bwb_OPTION_ARITHMETIC_NATIVE( l );
  2981. break;
  2982. case C_OPTION_BASE:
  2983. r = bwb_OPTION_BASE( l );
  2984. break;
  2985. case C_OPTION_BUGS:
  2986. r = bwb_OPTION_BUGS( l );
  2987. break;
  2988. case C_OPTION_BUGS_OFF:
  2989. r = bwb_OPTION_BUGS_OFF( l );
  2990. break;
  2991. case C_OPTION_BUGS_ON:
  2992. r = bwb_OPTION_BUGS_ON( l );
  2993. break;
  2994. case C_OPTION_COMMENT:
  2995. r = bwb_OPTION_COMMENT( l );
  2996. break;
  2997. case C_OPTION_COMPARE:
  2998. r = bwb_OPTION_COMPARE( l );
  2999. break;
  3000. case C_OPTION_COMPARE_BINARY:
  3001. r = bwb_OPTION_COMPARE_BINARY( l );
  3002. break;
  3003. case C_OPTION_COMPARE_DATABASE:
  3004. r = bwb_OPTION_COMPARE_DATABASE( l );
  3005. break;
  3006. case C_OPTION_COMPARE_TEXT:
  3007. r = bwb_OPTION_COMPARE_TEXT( l );
  3008. break;
  3009. case C_OPTION_COVERAGE:
  3010. r = bwb_OPTION_COVERAGE( l );
  3011. break;
  3012. case C_OPTION_COVERAGE_OFF:
  3013. r = bwb_OPTION_COVERAGE_OFF( l );
  3014. break;
  3015. case C_OPTION_COVERAGE_ON:
  3016. r = bwb_OPTION_COVERAGE_ON( l );
  3017. break;
  3018. case C_OPTION_DATE:
  3019. r = bwb_OPTION_DATE( l );
  3020. break;
  3021. case C_OPTION_DISABLE:
  3022. r = bwb_OPTION_DISABLE( l );
  3023. break;
  3024. case C_OPTION_DISABLE_COMMAND:
  3025. r = bwb_OPTION_DISABLE_COMMAND( l );
  3026. break;
  3027. case C_OPTION_DISABLE_FUNCTION:
  3028. r = bwb_OPTION_DISABLE_FUNCTION( l );
  3029. break;
  3030. case C_OPTION_DISABLE_OPERATOR:
  3031. r = bwb_OPTION_DISABLE_OPERATOR( l );
  3032. break;
  3033. case C_OPTION_ENABLE:
  3034. r = bwb_OPTION_ENABLE( l );
  3035. break;
  3036. case C_OPTION_ENABLE_COMMAND:
  3037. r = bwb_OPTION_ENABLE_COMMAND( l );
  3038. break;
  3039. case C_OPTION_ENABLE_FUNCTION:
  3040. r = bwb_OPTION_ENABLE_FUNCTION( l );
  3041. break;
  3042. case C_OPTION_ENABLE_OPERATOR:
  3043. r = bwb_OPTION_ENABLE_OPERATOR( l );
  3044. break;
  3045. case C_OPTION_ERROR:
  3046. r = bwb_OPTION_ERROR( l );
  3047. break;
  3048. case C_OPTION_ERROR_GOSUB:
  3049. r = bwb_OPTION_ERROR_GOSUB( l );
  3050. break;
  3051. case C_OPTION_ERROR_GOTO:
  3052. r = bwb_OPTION_ERROR_GOTO( l );
  3053. break;
  3054. case C_OPTION_EXPLICIT:
  3055. r = bwb_OPTION_EXPLICIT( l );
  3056. break;
  3057. case C_OPTION_IMAGE:
  3058. r = bwb_OPTION_IMAGE( l );
  3059. break;
  3060. case C_OPTION_IMPLICIT:
  3061. r = bwb_OPTION_IMPLICIT( l );
  3062. break;
  3063. case C_OPTION_INDENT:
  3064. r = bwb_OPTION_INDENT( l );
  3065. break;
  3066. case C_OPTION_LABELS:
  3067. r = bwb_OPTION_LABELS( l );
  3068. break;
  3069. case C_OPTION_LABELS_OFF:
  3070. r = bwb_OPTION_LABELS_OFF( l );
  3071. break;
  3072. case C_OPTION_LABELS_ON:
  3073. r = bwb_OPTION_LABELS_ON( l );
  3074. break;
  3075. case C_OPTION_PRINT:
  3076. r = bwb_OPTION_PRINT( l );
  3077. break;
  3078. case C_OPTION_ROUND:
  3079. r = bwb_OPTION_ROUND( l );
  3080. break;
  3081. case C_OPTION_ROUND_BANK:
  3082. r = bwb_OPTION_ROUND_BANK( l );
  3083. break;
  3084. case C_OPTION_ROUND_MATH:
  3085. r = bwb_OPTION_ROUND_MATH( l );
  3086. break;
  3087. case C_OPTION_ROUND_TRUNCATE:
  3088. r = bwb_OPTION_ROUND_TRUNCATE( l );
  3089. break;
  3090. case C_OPTION_SLEEP:
  3091. r = bwb_OPTION_SLEEP( l );
  3092. break;
  3093. case C_OPTION_STATEMENT:
  3094. r = bwb_OPTION_STATEMENT( l );
  3095. break;
  3096. case C_OPTION_STDERR:
  3097. r = bwb_OPTION_STDERR( l );
  3098. break;
  3099. case C_OPTION_STDIN:
  3100. r = bwb_OPTION_STDIN( l );
  3101. break;
  3102. case C_OPTION_STDOUT:
  3103. r = bwb_OPTION_STDOUT( l );
  3104. break;
  3105. case C_OPTION_STRICT:
  3106. r = bwb_OPTION_STRICT( l );
  3107. break;
  3108. case C_OPTION_STRICT_OFF:
  3109. r = bwb_OPTION_STRICT_OFF( l );
  3110. break;
  3111. case C_OPTION_STRICT_ON:
  3112. r = bwb_OPTION_STRICT_ON( l );
  3113. break;
  3114. case C_OPTION_TERMINAL:
  3115. r = bwb_OPTION_TERMINAL( l );
  3116. break;
  3117. case C_OPTION_TERMINAL_ADM:
  3118. r = bwb_OPTION_TERMINAL_ADM( l );
  3119. break;
  3120. case C_OPTION_TERMINAL_ANSI:
  3121. r = bwb_OPTION_TERMINAL_ANSI( l );
  3122. break;
  3123. case C_OPTION_TERMINAL_NONE:
  3124. r = bwb_OPTION_TERMINAL_NONE( l );
  3125. break;
  3126. case C_OPTION_TIME:
  3127. r = bwb_OPTION_TIME( l );
  3128. break;
  3129. case C_OPTION_TRACE:
  3130. r = bwb_OPTION_TRACE( l );
  3131. break;
  3132. case C_OPTION_TRACE_OFF:
  3133. r = bwb_OPTION_TRACE_OFF( l );
  3134. break;
  3135. case C_OPTION_TRACE_ON:
  3136. r = bwb_OPTION_TRACE_ON( l );
  3137. break;
  3138. case C_OPTION_USING:
  3139. r = bwb_OPTION_USING( l );
  3140. break;
  3141. case C_OPTION_VERSION:
  3142. r = bwb_OPTION_VERSION( l );
  3143. break;
  3144. case C_PAUSE:
  3145. r = bwb_PAUSE( l );
  3146. break;
  3147. case C_POP:
  3148. r = bwb_POP( l );
  3149. break;
  3150. case C_PRINT:
  3151. r = bwb_PRINT( l );
  3152. break;
  3153. case C_PUT:
  3154. r = bwb_PUT( l );
  3155. break;
  3156. case C_QUIT:
  3157. r = bwb_QUIT( l );
  3158. break;
  3159. case C_READ:
  3160. r = bwb_READ( l );
  3161. break;
  3162. case C_RECALL:
  3163. r = bwb_RECALL( l );
  3164. break;
  3165. case C_REM:
  3166. r = bwb_REM( l );
  3167. break;
  3168. case C_RENAME:
  3169. r = bwb_RENAME( l );
  3170. break;
  3171. case C_RENUM:
  3172. r = bwb_RENUM( l );
  3173. break;
  3174. case C_RENUMBER:
  3175. r = bwb_RENUMBER( l );
  3176. break;
  3177. case C_RESET:
  3178. r = bwb_RESET( l );
  3179. break;
  3180. case C_RESTORE:
  3181. r = bwb_RESTORE( l );
  3182. break;
  3183. case C_RESUME:
  3184. r = bwb_RESUME( l );
  3185. break;
  3186. case C_RETURN:
  3187. r = bwb_RETURN( l );
  3188. break;
  3189. case C_RSET:
  3190. r = bwb_RSET( l );
  3191. break;
  3192. case C_RUN:
  3193. r = bwb_RUN( l );
  3194. break;
  3195. case C_SAVE:
  3196. r = bwb_SAVE( l );
  3197. break;
  3198. case C_SCRATCH:
  3199. r = bwb_SCRATCH( l );
  3200. break;
  3201. case C_SELECT:
  3202. r = bwb_SELECT( l );
  3203. break;
  3204. case C_SELECT_CASE:
  3205. r = bwb_SELECT_CASE( l );
  3206. break;
  3207. case C_STEP:
  3208. r = bwb_STEP( l );
  3209. break;
  3210. case C_STOP:
  3211. r = bwb_STOP( l );
  3212. break;
  3213. case C_STORE:
  3214. r = bwb_STORE( l );
  3215. break;
  3216. case C_SUB:
  3217. r = bwb_SUB( l );
  3218. break;
  3219. case C_SUBEND:
  3220. r = bwb_SUBEND( l );
  3221. break;
  3222. case C_SWAP:
  3223. r = bwb_SWAP( l );
  3224. break;
  3225. case C_SYSTEM:
  3226. r = bwb_SYSTEM( l );
  3227. break;
  3228. case C_TEXT:
  3229. r = bwb_TEXT( l );
  3230. break;
  3231. case C_THEN:
  3232. r = bwb_THEN( l );
  3233. break;
  3234. case C_TIMER:
  3235. r = bwb_TIMER( l );
  3236. break;
  3237. case C_TIMER_OFF:
  3238. r = bwb_TIMER_OFF( l );
  3239. break;
  3240. case C_TIMER_ON:
  3241. r = bwb_TIMER_ON( l );
  3242. break;
  3243. case C_TIMER_STOP:
  3244. r = bwb_TIMER_STOP( l );
  3245. break;
  3246. case C_TLOAD:
  3247. r = bwb_TLOAD( l );
  3248. break;
  3249. case C_TO:
  3250. r = bwb_TO( l );
  3251. break;
  3252. case C_TRACE:
  3253. r = bwb_TRACE( l );
  3254. break;
  3255. case C_TRACE_OFF:
  3256. r = bwb_TRACE_OFF( l );
  3257. break;
  3258. case C_TRACE_ON:
  3259. r = bwb_TRACE_ON( l );
  3260. break;
  3261. case C_TSAVE:
  3262. r = bwb_TSAVE( l );
  3263. break;
  3264. case C_UEND:
  3265. r = bwb_UEND( l );
  3266. break;
  3267. case C_UNTIL:
  3268. r = bwb_UNTIL( l );
  3269. break;
  3270. case C_USE:
  3271. r = bwb_USE( l );
  3272. break;
  3273. case C_USER_LBL:
  3274. r = bwb_USER_LBL( l );
  3275. break;
  3276. case C_VARS:
  3277. r = bwb_VARS( l );
  3278. break;
  3279. case C_WEND:
  3280. r = bwb_WEND( l );
  3281. break;
  3282. case C_WHILE:
  3283. r = bwb_WHILE( l );
  3284. break;
  3285. case C_WRITE:
  3286. r = bwb_WRITE( l );
  3287. break;
  3288. default:
  3289. WARN_INTERNAL_ERROR;
  3290. r = l;
  3291. break;
  3292. }
  3293. return r;
  3294. }
  3295. /* EOF */