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.
 
 
 
 
 
 

2409 lines
54 KiB

  1. /***************************************************************
  2. bwb_cnd.c Conditional Expressions and Commands
  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. #include <stdio.h>
  18. #include <math.h>
  19. #include <ctype.h>
  20. #include "bwbasic.h"
  21. #include "bwb_mes.h"
  22. /* declarations of functions visible to this file only */
  23. #if ANSI_C
  24. static int cnd_thenels( char *buffer, int position, int *then, int *els );
  25. static int cnd_tostep( char *buffer, int position, int *to, int *step );
  26. static struct bwb_line *find_wend( struct bwb_line *l );
  27. static struct bwb_line *find_endif( struct bwb_line *l,
  28. struct bwb_line **else_line );
  29. static int is_endif( struct bwb_line *l );
  30. extern int var_setnval( struct bwb_variable *v, bnumber i );
  31. static int case_eval( struct exp_ese *expression, struct exp_ese *minval,
  32. struct exp_ese *maxval );
  33. static struct bwb_line *find_case( struct bwb_line *l );
  34. static struct bwb_line *find_endselect( struct bwb_line *l );
  35. static int is_endselect( struct bwb_line *l );
  36. static struct bwb_line *bwb_caseif( struct bwb_line *l );
  37. #if STRUCT_CMDS
  38. static struct bwb_line *find_next( struct bwb_line *l );
  39. #endif
  40. #else
  41. static int cnd_thenels();
  42. static int cnd_tostep();
  43. static struct bwb_line *find_wend();
  44. static struct bwb_line *find_endif();
  45. static int is_endif();
  46. extern int var_setnval();
  47. static int case_eval();
  48. static struct bwb_line *find_case();
  49. static struct bwb_line *find_endselect();
  50. static int is_endselect();
  51. static struct bwb_line *bwb_caseif();
  52. #if STRUCT_CMDS
  53. static struct bwb_line *find_next();
  54. #endif
  55. #endif /* ANSI_C for prototypes */
  56. /*** IF-THEN-ELSE ***/
  57. /***************************************************************
  58. FUNCTION: bwb_if()
  59. DESCRIPTION: This function handles the BASIC IF
  60. statement.
  61. SYNTAX: IF expression THEN [statement [ELSE statement]]
  62. ***************************************************************/
  63. #if ANSI_C
  64. struct bwb_line *
  65. bwb_if( struct bwb_line *l )
  66. #else
  67. struct bwb_line *
  68. bwb_if( l )
  69. struct bwb_line *l;
  70. #endif
  71. {
  72. int then, els;
  73. struct exp_ese *e;
  74. int glnumber;
  75. int tpos;
  76. static char tbuf[ MAXSTRINGSIZE + 1 ];
  77. static struct bwb_line gline;
  78. #if STRUCT_CMDS
  79. static struct bwb_line *else_line;
  80. static struct bwb_line *endif_line;
  81. #endif
  82. #if INTENSIVE_DEBUG
  83. sprintf( bwb_ebuf, "in bwb_if(): entry, line <%d> buffer <%s>",
  84. l->number, &( l->buffer[ l->position ] ) );
  85. bwb_debug( bwb_ebuf );
  86. getchar();
  87. #endif
  88. #if INTENSIVE_DEBUG
  89. if ( l == &gline )
  90. {
  91. sprintf( bwb_ebuf, "in bwb_if(): recursive call, l = &gline" );
  92. bwb_debug( bwb_ebuf );
  93. }
  94. #endif
  95. /* Call bwb_exp() to evaluate the condition. This should return
  96. with position set to the "THEN" statement */
  97. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  98. #if INTENSIVE_DEBUG
  99. sprintf( bwb_ebuf, "in bwb_if(): line <%d> condition returns <%d>",
  100. l->number, exp_getnval( e ) );
  101. bwb_debug( bwb_ebuf );
  102. #endif
  103. /* test for "THEN" and "ELSE" statements */
  104. cnd_thenels( l->buffer, l->position, &then, &els );
  105. #if INTENSIVE_DEBUG
  106. sprintf( bwb_ebuf, "in bwb_if(): return from cnd_thenelse, line is <%s>",
  107. l->buffer );
  108. bwb_debug( bwb_ebuf );
  109. #endif
  110. /* test for multiline IF statement: this presupposes ANSI-compliant
  111. structured BASIC */
  112. #if STRUCT_CMDS
  113. tpos = then + strlen( CMD_THEN ) + 1;
  114. if ( is_eol( l->buffer, &tpos ) == TRUE )
  115. {
  116. #if INTENSIVE_DEBUG
  117. sprintf( bwb_ebuf, "in bwb_if(): found multi-line IF statement, line <%d>",
  118. l->number );
  119. bwb_debug( bwb_ebuf );
  120. #endif
  121. /* find END IF and possibly ELSE[IF] line(s) */
  122. else_line = NULL;
  123. endif_line = find_endif( l, &else_line );
  124. /* evaluate the expression */
  125. if ( (int) exp_getnval( e ) != FALSE )
  126. {
  127. bwb_incexec();
  128. bwb_setexec( l->next, 0, EXEC_IFTRUE );
  129. #if MULTISEG_LINES
  130. adv_eos( l->buffer, &( l->position ));
  131. #endif
  132. return bwb_zline( l );
  133. }
  134. else if ( else_line != NULL )
  135. {
  136. bwb_incexec();
  137. bwb_setexec( else_line, 0, EXEC_IFFALSE );
  138. else_line->position = 0;
  139. return else_line;
  140. }
  141. else
  142. {
  143. bwb_setexec( endif_line, 0, CURTASK excs[ CURTASK exsc ].code );
  144. endif_line->position = 0;
  145. return endif_line;
  146. }
  147. }
  148. #endif /* STRUCT_CMDS for Multi-line IF...THEN */
  149. /* Not a Multi-line IF...THEN: test for THEN line-number */
  150. #if INTENSIVE_DEBUG
  151. sprintf( bwb_ebuf, "in bwb_if(): not multi-line; line is <%s>",
  152. l->buffer );
  153. bwb_debug( bwb_ebuf );
  154. #endif
  155. /* evaluate and execute */
  156. if ( (int) exp_getnval( e ) != FALSE )
  157. {
  158. #if INTENSIVE_DEBUG
  159. sprintf( bwb_ebuf, "in bwb_if(): expression is TRUE" );
  160. bwb_debug( bwb_ebuf );
  161. #endif
  162. if ( then == FALSE )
  163. {
  164. #if PROG_ERRORS
  165. sprintf( bwb_ebuf, "in bwb_if(): IF without THEN" );
  166. bwb_error( bwb_ebuf );
  167. #else
  168. bwb_error( err_syntax );
  169. #endif
  170. }
  171. else
  172. {
  173. /* check for THEN followed by literal line number */
  174. tpos = then + strlen( CMD_THEN ) + 1;
  175. adv_element( l->buffer, &tpos, tbuf );
  176. if ( isdigit( tbuf[ 0 ] ) != 0 )
  177. {
  178. glnumber = atoi( tbuf );
  179. #if INTENSIVE_DEBUG
  180. sprintf( bwb_ebuf, "Detected THEN followed by line number <%d>",
  181. glnumber );
  182. bwb_debug( bwb_ebuf );
  183. #endif
  184. sprintf( tbuf, "%s %d", CMD_GOTO, glnumber );
  185. gline.buffer = tbuf;
  186. gline.marked = FALSE;
  187. gline.position = 0;
  188. gline.next = l->next;
  189. bwb_setexec( &gline, 0, CURTASK excs[ CURTASK exsc ].code );
  190. return &gline;
  191. }
  192. /* form is not THEN followed by line number */
  193. else
  194. {
  195. bwb_setexec( l, then, CURTASK excs[ CURTASK exsc ].code );
  196. l->position = then + strlen( CMD_THEN ) + 1;
  197. }
  198. return l;
  199. }
  200. }
  201. else
  202. {
  203. #if INTENSIVE_DEBUG
  204. sprintf( bwb_ebuf, "in bwb_if(): expression is FALSE" );
  205. bwb_debug( bwb_ebuf );
  206. #endif
  207. if ( els != FALSE )
  208. {
  209. l->position = els + strlen( CMD_ELSE ) + 1;
  210. bwb_setexec( l, els, EXEC_NORM );
  211. return l;
  212. }
  213. }
  214. /* if neither then nor else were found, advance to next line */
  215. /* DO NOT advance to next segment (only if TRUE should we do that */
  216. l->next->position = 0;
  217. return l->next;
  218. }
  219. /***************************************************************
  220. FUNCTION: cnd_thenelse()
  221. DESCRIPTION: This function searches through the
  222. <buffer> beginning at point <position>
  223. and attempts to find positions of THEN
  224. and ELSE statements.
  225. ***************************************************************/
  226. #if ANSI_C
  227. static int
  228. cnd_thenels( char *buffer, int position, int *then, int *els )
  229. #else
  230. static int
  231. cnd_thenels( buffer, position, then, els )
  232. char *buffer;
  233. int position;
  234. int *then;
  235. int *els;
  236. #endif
  237. {
  238. int loop, t_pos, b_pos, p_word;
  239. char tbuf[ MAXSTRINGSIZE + 1 ];
  240. #if INTENSIVE_DEBUG
  241. sprintf( bwb_ebuf, "in cnd_thenels(): entry, line is <%s>",
  242. &( buffer[ position ] ) );
  243. bwb_debug( bwb_ebuf );
  244. #endif
  245. /* set then and els to 0 initially */
  246. *then = *els = 0;
  247. /* loop to find words */
  248. p_word = b_pos = position;
  249. t_pos = 0;
  250. tbuf[ 0 ] = '\0';
  251. loop = TRUE;
  252. while( loop == TRUE )
  253. {
  254. switch( buffer[ b_pos ] )
  255. {
  256. case '\0': /* end of string */
  257. case ' ': /* whitespace = end of word */
  258. case '\t':
  259. #if INTENSIVE_DEBUG
  260. sprintf( bwb_ebuf, "in cnd_thenels(): word is <%s>", tbuf );
  261. bwb_debug( bwb_ebuf );
  262. #endif
  263. if ( strncmp( tbuf, CMD_THEN, (size_t) strlen( CMD_THEN ) ) == 0 )
  264. {
  265. #if INTENSIVE_DEBUG
  266. sprintf( bwb_ebuf, "in cnd_thenels(): THEN found at position <%d>.",
  267. p_word );
  268. bwb_debug( bwb_ebuf );
  269. sprintf( bwb_ebuf, "in cnd_thenelse(): after THEN, line is <%s>", buffer );
  270. bwb_debug( bwb_ebuf );
  271. #endif
  272. *then = p_word;
  273. }
  274. else if ( strncmp( tbuf, CMD_ELSE, (size_t) strlen( CMD_ELSE ) ) == 0 )
  275. {
  276. #if INTENSIVE_DEBUG
  277. sprintf( bwb_ebuf, "in cnd_thenels(): ELSE found at position <%d>.",
  278. p_word );
  279. bwb_debug( bwb_ebuf );
  280. sprintf( bwb_ebuf, "in cnd_thenelse(): after ELSE, line is <%s>", buffer );
  281. bwb_debug( bwb_ebuf );
  282. #endif
  283. *els = p_word;
  284. }
  285. /* check for end of the line */
  286. if ( buffer[ b_pos ] == '\0' )
  287. {
  288. #if INTENSIVE_DEBUG
  289. sprintf( bwb_ebuf, "in cnd_thenels(): return: end of string" );
  290. bwb_debug( bwb_ebuf );
  291. #endif
  292. return TRUE;
  293. }
  294. ++b_pos;
  295. p_word = b_pos;
  296. t_pos = 0;
  297. tbuf[ 0 ] = '\0';
  298. break;
  299. default:
  300. if ( islower( buffer[ b_pos ] ) != FALSE )
  301. {
  302. tbuf[ t_pos ] = (char) toupper( buffer[ b_pos ] );
  303. }
  304. else
  305. {
  306. tbuf[ t_pos ] = buffer[ b_pos ];
  307. }
  308. ++b_pos;
  309. ++t_pos;
  310. tbuf[ t_pos ] = '\0';
  311. break;
  312. }
  313. }
  314. #if INTENSIVE_DEBUG
  315. sprintf( bwb_ebuf, "in cnd_thenelse(): exit, line is <%s>", buffer );
  316. bwb_debug( bwb_ebuf );
  317. #endif
  318. return FALSE;
  319. }
  320. #if STRUCT_CMDS
  321. /***************************************************************
  322. FUNCTION: bwb_else()
  323. DESCRIPTION: This function handles the BASIC ELSE
  324. statement.
  325. SYNTAX: ELSE
  326. ***************************************************************/
  327. #if ANSI_C
  328. struct bwb_line *
  329. bwb_else( struct bwb_line *l )
  330. #else
  331. struct bwb_line *
  332. bwb_else( l )
  333. struct bwb_line *l;
  334. #endif
  335. {
  336. struct bwb_line *endif_line;
  337. struct bwb_line *else_line;
  338. #if INTENSIVE_DEBUG
  339. sprintf( bwb_ebuf, "in bwb_else(): entered function" );
  340. bwb_debug( bwb_ebuf );
  341. #endif
  342. /* If the code is EXEC_NORM, then this is a continuation of a single-
  343. line IF...THEN...ELSE... statement and we should return */
  344. if ( CURTASK excs[ CURTASK exsc ].code == EXEC_NORM )
  345. {
  346. #if INTENSIVE_DEBUG
  347. sprintf( bwb_ebuf, "in bwb_else(): detected EXEC_NORM" );
  348. bwb_debug( bwb_ebuf );
  349. #endif
  350. return bwb_zline( l );
  351. }
  352. endif_line = find_endif( l, &else_line );
  353. if ( CURTASK excs[ CURTASK exsc ].code == EXEC_IFTRUE )
  354. {
  355. endif_line->position = 0;
  356. return endif_line;
  357. }
  358. else if ( CURTASK excs[ CURTASK exsc ].code == EXEC_IFFALSE )
  359. {
  360. return bwb_zline( l );
  361. }
  362. #if PROG_ERRORS
  363. sprintf( bwb_ebuf, "in bwb_else(): ELSE without IF" );
  364. bwb_error( bwb_ebuf );
  365. #else
  366. bwb_error( err_syntax );
  367. #endif
  368. return bwb_zline( l );
  369. }
  370. /***************************************************************
  371. FUNCTION: bwb_elseif()
  372. DESCRIPTION: This function handles the BASIC ELSEIF
  373. statement.
  374. SYNTAX: ELSEIF
  375. ***************************************************************/
  376. #if ANSI_C
  377. struct bwb_line *
  378. bwb_elseif( struct bwb_line *l )
  379. #else
  380. struct bwb_line *
  381. bwb_elseif( l )
  382. struct bwb_line *l;
  383. #endif
  384. {
  385. struct bwb_line *endif_line;
  386. struct bwb_line *else_line;
  387. struct exp_ese *e;
  388. #if INTENSIVE_DEBUG
  389. sprintf( bwb_ebuf, "in bwb_elseif(): entered function" );
  390. bwb_debug( bwb_ebuf );
  391. #endif
  392. else_line = NULL;
  393. endif_line = find_endif( l, &else_line );
  394. if ( CURTASK excs[ CURTASK exsc ].code == EXEC_IFTRUE )
  395. {
  396. endif_line->position = 0;
  397. return endif_line;
  398. }
  399. else if ( CURTASK excs[ CURTASK exsc ].code == EXEC_IFFALSE )
  400. {
  401. /* Call bwb_exp() to evaluate the condition. This should return
  402. with position set to the "THEN" statement */
  403. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  404. if ( (int) exp_getnval( e ) == TRUE )
  405. {
  406. /* ELSEIF condition is TRUE: proceed to the next line */
  407. CURTASK excs[ CURTASK exsc ].code = EXEC_IFTRUE;
  408. #if MULTISEG_LINES
  409. adv_eos( l->buffer, &( l->position ));
  410. #endif
  411. return bwb_zline( l );
  412. }
  413. /* ELSEIF condition FALSE: proceed to next ELSE line if there is one */
  414. else if ( else_line != NULL )
  415. {
  416. bwb_setexec( else_line, 0, EXEC_IFFALSE );
  417. else_line->position = 0;
  418. return else_line;
  419. }
  420. /* ELSEIF condition is FALSE and no more ELSExx lines: proceed to END IF */
  421. else
  422. {
  423. bwb_setexec( endif_line, 0, CURTASK excs[ CURTASK exsc ].code );
  424. endif_line->position = 0;
  425. return endif_line;
  426. }
  427. }
  428. #if PROG_ERRORS
  429. sprintf( bwb_ebuf, "in bwb_elseif(): ELSEIF without IF" );
  430. bwb_error( bwb_ebuf );
  431. #else
  432. bwb_error( err_syntax );
  433. #endif
  434. #if MULTISEG_LINES
  435. adv_eos( l->buffer, &( l->position ));
  436. #endif
  437. return bwb_zline( l );
  438. }
  439. /***************************************************************
  440. FUNCTION: bwb_endif()
  441. DESCRIPTION: This function handles the BASIC END IF
  442. statement.
  443. SYNTAX: END IF
  444. ***************************************************************/
  445. #if ANSI_C
  446. struct bwb_line *
  447. bwb_endif( struct bwb_line *l )
  448. #else
  449. struct bwb_line *
  450. bwb_endif( l )
  451. struct bwb_line *l;
  452. #endif
  453. {
  454. #if INTENSIVE_DEBUG
  455. sprintf( bwb_ebuf, "in bwb_endif(): entered function" );
  456. bwb_debug( bwb_ebuf );
  457. #endif
  458. if (( CURTASK excs[ CURTASK exsc ].code != EXEC_IFTRUE )
  459. && ( CURTASK excs[ CURTASK exsc ].code != EXEC_IFFALSE ))
  460. {
  461. #if PROG_ERRORS
  462. sprintf( bwb_ebuf, "in bwb_endif(): END IF without IF" );
  463. bwb_error( bwb_ebuf );
  464. #else
  465. bwb_error( err_syntax );
  466. #endif
  467. }
  468. bwb_decexec();
  469. #if MULTISEG_LINES
  470. adv_eos( l->buffer, &( l->position ));
  471. #endif
  472. return bwb_zline( l );
  473. }
  474. /***************************************************************
  475. FUNCTION: find_endif()
  476. DESCRIPTION: This C function attempts to find an
  477. END IF statement.
  478. ***************************************************************/
  479. #if ANSI_C
  480. static struct bwb_line *
  481. find_endif( struct bwb_line *l, struct bwb_line **else_line )
  482. #else
  483. static struct bwb_line *
  484. find_endif( l, else_line )
  485. struct bwb_line *l;
  486. struct bwb_line **else_line;
  487. #endif
  488. {
  489. struct bwb_line *current;
  490. register int i_level;
  491. int position;
  492. *else_line = NULL;
  493. i_level = 1;
  494. for ( current = l->next; current != &CURTASK bwb_end; current = current->next )
  495. {
  496. position = 0;
  497. if ( current->marked != TRUE )
  498. {
  499. line_start( current->buffer, &position, &( current->lnpos ),
  500. &( current->lnum ),
  501. &( current->cmdpos ),
  502. &( current->cmdnum ),
  503. &( current->startpos ) );
  504. }
  505. current->position = current->startpos;
  506. if ( current->cmdnum > -1 )
  507. {
  508. if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_if )
  509. {
  510. ++i_level;
  511. #if INTENSIVE_DEBUG
  512. sprintf( bwb_ebuf, "in find_endif(): found IF at line %d, level %d",
  513. current->number, i_level );
  514. bwb_debug( bwb_ebuf );
  515. #endif
  516. }
  517. else if ( is_endif( current ) == TRUE )
  518. {
  519. --i_level;
  520. #if INTENSIVE_DEBUG
  521. sprintf( bwb_ebuf, "in find_endif(): found END IF at line %d, level %d",
  522. current->number, i_level );
  523. bwb_debug( bwb_ebuf );
  524. #endif
  525. if ( i_level == 0 )
  526. {
  527. return current;
  528. }
  529. }
  530. else if ( ( bwb_cmdtable[ current->cmdnum ].vector == bwb_else )
  531. || ( bwb_cmdtable[ current->cmdnum ].vector == bwb_elseif ))
  532. {
  533. /* we must only report the first ELSE or ELSE IF we encounter
  534. at level 1 */
  535. if ( ( i_level == 1 ) && ( *else_line == NULL ))
  536. {
  537. *else_line = current;
  538. }
  539. }
  540. }
  541. }
  542. #if PROG_ERRORS
  543. sprintf( bwb_ebuf, "Multiline IF without END IF" );
  544. bwb_error( bwb_ebuf );
  545. #else
  546. bwb_error( err_syntax );
  547. #endif
  548. return NULL;
  549. }
  550. /***************************************************************
  551. FUNCTION: is_endif()
  552. DESCRIPTION: This C function attempts to determine if
  553. a given line contains an END IF statement.
  554. ***************************************************************/
  555. #if ANSI_C
  556. static int
  557. is_endif( struct bwb_line *l )
  558. #else
  559. static int
  560. is_endif( l )
  561. struct bwb_line *l;
  562. #endif
  563. {
  564. int position;
  565. char tbuf[ MAXVARNAMESIZE + 1];
  566. if ( bwb_cmdtable[ l->cmdnum ].vector != bwb_xend )
  567. {
  568. return FALSE;
  569. }
  570. position = l->startpos;
  571. adv_ws( l->buffer, &position );
  572. adv_element( l->buffer, &position, tbuf );
  573. bwb_strtoupper( tbuf );
  574. if ( strcmp( tbuf, "IF" ) == 0 )
  575. {
  576. return TRUE;
  577. }
  578. return FALSE;
  579. }
  580. /***************************************************************
  581. FUNCTION: bwb_select()
  582. DESCRIPTION: This C function handles the BASIC SELECT
  583. statement.
  584. SYNTAX: SELECT CASE expression
  585. ***************************************************************/
  586. #if ANSI_C
  587. struct bwb_line *
  588. bwb_select( struct bwb_line *l )
  589. #else
  590. struct bwb_line *
  591. bwb_select( l )
  592. struct bwb_line *l;
  593. #endif
  594. {
  595. char tbuf[ MAXSTRINGSIZE + 1 ];
  596. struct exp_ese *e;
  597. #if INTENSIVE_DEBUG
  598. sprintf( bwb_ebuf, "in bwb_select(): entered function" );
  599. bwb_debug( bwb_ebuf );
  600. #endif
  601. /* first element should be "CASE" */
  602. adv_element( l->buffer, &( l->position ), tbuf );
  603. bwb_strtoupper( tbuf );
  604. if ( strcmp( tbuf, "CASE" ) != 0 )
  605. {
  606. #if PROG_ERRORS
  607. sprintf( bwb_ebuf, "SELECT without CASE" );
  608. bwb_error( bwb_ebuf );
  609. #else
  610. bwb_error( err_syntax );
  611. return bwb_zline( l );
  612. #endif
  613. }
  614. /* increment the level and set to EXEC_SELFALSE */
  615. bwb_incexec();
  616. CURTASK excs[ CURTASK exsc ].code = EXEC_SELFALSE;
  617. /* evaluate the expression at this level */
  618. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  619. #if OLDWAY
  620. memcpy( &( CURTASK excs[ CURTASK exsc ].expression ), e,
  621. sizeof( struct exp_ese ) );
  622. #endif
  623. if ( e->type == STRING )
  624. {
  625. CURTASK excs[ CURTASK exsc ].expression.type = STRING;
  626. str_btob( &( CURTASK excs[ CURTASK exsc ].expression.sval ),
  627. &( e->sval ) );
  628. }
  629. else
  630. {
  631. CURTASK excs[ CURTASK exsc ].expression.type = NUMBER;
  632. CURTASK excs[ CURTASK exsc ].expression.nval
  633. = exp_getnval( e );
  634. }
  635. /* return */
  636. #if MULTISEG_LINES
  637. adv_eos( l->buffer, &( l->position ));
  638. #endif
  639. return bwb_zline( l );
  640. }
  641. /***************************************************************
  642. FUNCTION: bwb_case()
  643. DESCRIPTION: This C function handles the BASIC CASE
  644. statement.
  645. SYNTAX: CASE constant | IF partial-expression | ELSE
  646. ***************************************************************/
  647. #if ANSI_C
  648. struct bwb_line *
  649. bwb_case( struct bwb_line *l )
  650. #else
  651. struct bwb_line *
  652. bwb_case( l )
  653. struct bwb_line *l;
  654. #endif
  655. {
  656. char tbuf[ MAXSTRINGSIZE + 1 ];
  657. int oldpos;
  658. struct exp_ese minvalue;
  659. struct exp_ese *maxval, *minval;
  660. struct bwb_line *retline;
  661. char cbuf1[ MAXSTRINGSIZE + 1 ];
  662. char cbuf2[ MAXSTRINGSIZE + 1 ];
  663. #if INTENSIVE_DEBUG
  664. sprintf( bwb_ebuf, "in bwb_case(): entered function" );
  665. bwb_debug( bwb_ebuf );
  666. #endif
  667. /* if code is EXEC_SELTRUE, then we should jump to the end */
  668. if ( CURTASK excs[ CURTASK exsc ].code == EXEC_SELTRUE )
  669. {
  670. #if INTENSIVE_DEBUG
  671. sprintf( bwb_ebuf, "in bwb_case(): exit EXEC_SELTRUE" );
  672. bwb_debug( bwb_ebuf );
  673. #endif
  674. retline = find_endselect( l );
  675. retline->position = 0;
  676. return retline;
  677. }
  678. /* read first element */
  679. oldpos = l->position;
  680. adv_element( l->buffer, &( l->position ), tbuf );
  681. bwb_strtoupper( tbuf );
  682. /* check for CASE IF */
  683. if ( strcmp( tbuf, CMD_IF ) == 0 )
  684. {
  685. return bwb_caseif( l );
  686. }
  687. /* check for CASE ELSE: if true, simply proceed to the next line,
  688. because other options should have been detected by now */
  689. else if ( strcmp( tbuf, CMD_ELSE ) == 0 )
  690. {
  691. #if INTENSIVE_DEBUG
  692. sprintf( bwb_ebuf, "in bwb_case(): execute CASE ELSE" );
  693. bwb_debug( bwb_ebuf );
  694. #endif
  695. return bwb_zline( l );
  696. }
  697. /* neither CASE ELSE nor CASE IF; presume constant here for min value */
  698. l->position = oldpos;
  699. minval = bwb_exp( l->buffer, FALSE, &( l->position ));
  700. memcpy( &minvalue, minval, sizeof( struct exp_ese ) );
  701. maxval = minval = &minvalue;
  702. /* check for string value */
  703. if ( minvalue.type == STRING )
  704. {
  705. str_btoc( cbuf1, &( CURTASK excs[ CURTASK exsc ].expression.sval ) );
  706. str_btoc( cbuf2, &( minvalue.sval ) );
  707. #if INTENSIVE_DEBUG
  708. sprintf( bwb_ebuf, "in bwb_case(): compare strings <%s> and <%s>",
  709. cbuf1, cbuf2 );
  710. bwb_debug( bwb_ebuf );
  711. #endif
  712. if ( strncmp( cbuf1, cbuf2, MAXSTRINGSIZE ) == 0 )
  713. {
  714. #if INTENSIVE_DEBUG
  715. sprintf( bwb_ebuf, "in bwb_case(): string comparison returns TRUE" );
  716. bwb_debug( bwb_ebuf );
  717. #endif
  718. CURTASK excs[ CURTASK exsc ].code = EXEC_SELTRUE;
  719. #if MULTISEG_LINES
  720. adv_eos( l->buffer, &( l->position ));
  721. #endif
  722. return bwb_zline( l );
  723. }
  724. else
  725. {
  726. #if INTENSIVE_DEBUG
  727. sprintf( bwb_ebuf, "in bwb_case(): string comparison returns FALSE" );
  728. bwb_debug( bwb_ebuf );
  729. #endif
  730. retline = find_case( l );
  731. retline->position = 0;
  732. return retline;
  733. }
  734. }
  735. /* not a string; advance */
  736. adv_ws( l->buffer, &( l->position ));
  737. /* check for TO */
  738. if ( is_eol( l->buffer, &( l->position )) != TRUE )
  739. {
  740. /* find the TO statement */
  741. adv_element( l->buffer, &( l->position ), tbuf );
  742. bwb_strtoupper( tbuf );
  743. if ( strcmp( tbuf, CMD_TO ) != 0 )
  744. {
  745. #if PROG_ERRORS
  746. sprintf( bwb_ebuf, "CASE has inexplicable code following expression" );
  747. bwb_error( bwb_ebuf );
  748. #else
  749. bwb_error( err_syntax );
  750. #if MULTISEG_LINES
  751. adv_eos( l->buffer, &( l->position ));
  752. #endif
  753. return bwb_zline( l );
  754. #endif
  755. }
  756. /* now evaluate the MAX expression */
  757. maxval = bwb_exp( l->buffer, FALSE, &( l->position ));
  758. }
  759. /* evaluate the expression */
  760. if ( case_eval( &( CURTASK excs[ CURTASK exsc ].expression ),
  761. minval, maxval ) == TRUE )
  762. {
  763. #if INTENSIVE_DEBUG
  764. sprintf( bwb_ebuf, "in bwb_case(): evaluation returns TRUE" );
  765. bwb_debug( bwb_ebuf );
  766. #endif
  767. CURTASK excs[ CURTASK exsc ].code = EXEC_SELTRUE;
  768. #if MULTISEG_LINES
  769. adv_eos( l->buffer, &( l->position ));
  770. #endif
  771. return bwb_zline( l );
  772. }
  773. /* evaluation returns a FALSE value; find next CASE or END SELECT statement */
  774. else
  775. {
  776. #if INTENSIVE_DEBUGb
  777. sprintf( bwb_ebuf, "in bwb_case(): evaluation returns FALSE" );
  778. bwb_debug( bwb_ebuf );
  779. #endif
  780. retline = find_case( l );
  781. retline->position = 0;
  782. return retline;
  783. }
  784. }
  785. /***************************************************************
  786. FUNCTION: bwb_caseif()
  787. DESCRIPTION: This C function handles the BASIC CASE IF
  788. statement.
  789. ***************************************************************/
  790. #if ANSI_C
  791. static struct bwb_line *
  792. bwb_caseif( struct bwb_line *l )
  793. #else
  794. static struct bwb_line *
  795. bwb_caseif( l )
  796. struct bwb_line *l;
  797. #endif
  798. {
  799. char tbuf[ MAXSTRINGSIZE + 1 ];
  800. int position;
  801. struct exp_ese *r;
  802. struct bwb_line *retline;
  803. if ( CURTASK excs[ CURTASK exsc ].expression.type == NUMBER )
  804. {
  805. sprintf( tbuf, "%f %s",
  806. (float) CURTASK excs[ CURTASK exsc ].expression.nval,
  807. &( l->buffer[ l->position ] ) );
  808. }
  809. else
  810. {
  811. bwb_error( err_mismatch );
  812. #if MULTISEG_LINES
  813. adv_eos( l->buffer, &( l->position ));
  814. #endif
  815. return bwb_zline( l );
  816. }
  817. position = 0;
  818. r = bwb_exp( tbuf, FALSE, &position );
  819. if ( r->nval == (bnumber) TRUE )
  820. {
  821. CURTASK excs[ CURTASK exsc ].code = EXEC_SELTRUE;
  822. #if MULTISEG_LINES
  823. adv_eos( l->buffer, &( l->position ));
  824. #endif
  825. return bwb_zline( l );
  826. }
  827. else
  828. {
  829. retline = find_case( l );
  830. retline->position = 0;
  831. return retline;
  832. }
  833. }
  834. /***************************************************************
  835. FUNCTION: case_eval()
  836. DESCRIPTION: This function evaluates a case statement
  837. by comparing minimum and maximum values
  838. with a set expression. It returns either
  839. TRUE or FALSE
  840. ***************************************************************/
  841. #if ANSI_C
  842. static int
  843. case_eval( struct exp_ese *expression, struct exp_ese *minval,
  844. struct exp_ese *maxval )
  845. #else
  846. static int
  847. case_eval( expression, minval, maxval )
  848. struct exp_ese *expression;
  849. struct exp_ese *minval;
  850. struct exp_ese *maxval;
  851. #endif
  852. {
  853. /* string value */
  854. if ( expression->type == STRING )
  855. {
  856. bwb_error( err_mismatch );
  857. return FALSE;
  858. }
  859. /* numerical value */
  860. #if INTENSIVE_DEBUG
  861. sprintf( bwb_ebuf, "in case_eval(): n <%f> min <%f> max <%f>",
  862. (float) expression->nval,
  863. (float) minval->nval,
  864. (float) maxval->nval );
  865. bwb_debug( bwb_ebuf );
  866. #endif
  867. if ( ( expression->nval >= minval->nval )
  868. && ( expression->nval <= maxval->nval ))
  869. {
  870. return TRUE;
  871. }
  872. return FALSE;
  873. }
  874. /***************************************************************
  875. FUNCTION: find_case()
  876. DESCRIPTION: This function searches for a line containing
  877. a CASE statement corresponding to a previous
  878. SELECT CASE statement.
  879. ***************************************************************/
  880. #if ANSI_C
  881. static struct bwb_line *
  882. find_case( struct bwb_line *l )
  883. #else
  884. static struct bwb_line *
  885. find_case( l )
  886. struct bwb_line *l;
  887. #endif
  888. {
  889. struct bwb_line *current;
  890. register int c_level;
  891. int position;
  892. c_level = 1;
  893. for ( current = l->next; current != &CURTASK bwb_end; current = current->next )
  894. {
  895. position = 0;
  896. if ( current->marked != TRUE )
  897. {
  898. line_start( current->buffer, &position, &( current->lnpos ),
  899. &( current->lnum ),
  900. &( current->cmdpos ),
  901. &( current->cmdnum ),
  902. &( current->startpos ) );
  903. }
  904. current->position = current->startpos;
  905. if ( current->cmdnum > -1 )
  906. {
  907. if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_select )
  908. {
  909. ++c_level;
  910. #if INTENSIVE_DEBUG
  911. sprintf( bwb_ebuf, "in find_case(): found SELECT at line %d, level %d",
  912. current->number, c_level );
  913. bwb_debug( bwb_ebuf );
  914. #endif
  915. }
  916. else if ( is_endselect( current ) == TRUE )
  917. {
  918. --c_level;
  919. #if INTENSIVE_DEBUG
  920. sprintf( bwb_ebuf, "in find_endif(): found END SELECT at line %d, level %d",
  921. current->number, c_level );
  922. bwb_debug( bwb_ebuf );
  923. #endif
  924. if ( c_level == 0 )
  925. {
  926. return current;
  927. }
  928. }
  929. else if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_case )
  930. {
  931. --c_level;
  932. #if INTENSIVE_DEBUG
  933. sprintf( bwb_ebuf, "in find_case(): found CASE at line %d, level %d",
  934. current->number, c_level );
  935. bwb_debug( bwb_ebuf );
  936. #endif
  937. if ( c_level == 0 )
  938. {
  939. return current;
  940. }
  941. }
  942. }
  943. }
  944. #if PROG_ERRORS
  945. sprintf( bwb_ebuf, "SELECT without CASE" );
  946. bwb_error( bwb_ebuf );
  947. #else
  948. bwb_error( err_syntax );
  949. #endif
  950. return NULL;
  951. }
  952. /***************************************************************
  953. FUNCTION: find_case()
  954. DESCRIPTION: This function searches for a line containing
  955. an END SELECT statement corresponding to a previous
  956. SELECT CASE statement.
  957. ***************************************************************/
  958. #if ANSI_C
  959. static struct bwb_line *
  960. find_endselect( struct bwb_line *l )
  961. #else
  962. static struct bwb_line *
  963. find_endselect( l )
  964. struct bwb_line *l;
  965. #endif
  966. {
  967. struct bwb_line *current;
  968. register int c_level;
  969. int position;
  970. c_level = 1;
  971. for ( current = l->next; current != &CURTASK bwb_end; current = current->next )
  972. {
  973. position = 0;
  974. if ( current->marked != TRUE )
  975. {
  976. line_start( current->buffer, &position, &( current->lnpos ),
  977. &( current->lnum ),
  978. &( current->cmdpos ),
  979. &( current->cmdnum ),
  980. &( current->startpos ) );
  981. }
  982. current->position = current->startpos;
  983. if ( current->cmdnum > -1 )
  984. {
  985. if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_select )
  986. {
  987. ++c_level;
  988. #if INTENSIVE_DEBUG
  989. sprintf( bwb_ebuf, "in find_case(): found SELECT at line %d, level %d",
  990. current->number, c_level );
  991. bwb_debug( bwb_ebuf );
  992. #endif
  993. }
  994. else if ( is_endselect( current ) == TRUE )
  995. {
  996. --c_level;
  997. #if INTENSIVE_DEBUG
  998. sprintf( bwb_ebuf, "in find_endif(): found END SELECT at line %d, level %d",
  999. current->number, c_level );
  1000. bwb_debug( bwb_ebuf );
  1001. #endif
  1002. if ( c_level == 0 )
  1003. {
  1004. return current;
  1005. }
  1006. }
  1007. }
  1008. }
  1009. #if PROG_ERRORS
  1010. sprintf( bwb_ebuf, "SELECT without END SELECT" );
  1011. bwb_error( bwb_ebuf );
  1012. #else
  1013. bwb_error( err_syntax );
  1014. #endif
  1015. return NULL;
  1016. }
  1017. /***************************************************************
  1018. FUNCTION: is_endselect()
  1019. DESCRIPTION: This C function attempts to determine if
  1020. a given line contains an END SELECT statement.
  1021. ***************************************************************/
  1022. #if ANSI_C
  1023. static int
  1024. is_endselect( struct bwb_line *l )
  1025. #else
  1026. static int
  1027. is_endselect( l )
  1028. struct bwb_line *l;
  1029. #endif
  1030. {
  1031. int position;
  1032. char tbuf[ MAXVARNAMESIZE + 1];
  1033. if ( bwb_cmdtable[ l->cmdnum ].vector != bwb_xend )
  1034. {
  1035. return FALSE;
  1036. }
  1037. position = l->startpos;
  1038. adv_ws( l->buffer, &position );
  1039. adv_element( l->buffer, &position, tbuf );
  1040. bwb_strtoupper( tbuf );
  1041. if ( strcmp( tbuf, "SELECT" ) == 0 )
  1042. {
  1043. return TRUE;
  1044. }
  1045. return FALSE;
  1046. }
  1047. /***************************************************************
  1048. FUNCTION: bwb_endselect()
  1049. DESCRIPTION: This function handles the BASIC END
  1050. SELECT statement.
  1051. SYNTAX: END SELECT
  1052. ***************************************************************/
  1053. #if ANSI_C
  1054. struct bwb_line *
  1055. bwb_endselect( struct bwb_line *l )
  1056. #else
  1057. struct bwb_line *
  1058. bwb_endselect( l )
  1059. struct bwb_line *l;
  1060. #endif
  1061. {
  1062. #if INTENSIVE_DEBUG
  1063. sprintf( bwb_ebuf, "in bwb_endselect(): entered function" );
  1064. bwb_debug( bwb_ebuf );
  1065. #endif
  1066. if ( ( CURTASK excs[ CURTASK exsc ].code != EXEC_SELTRUE )
  1067. && ( CURTASK excs[ CURTASK exsc ].code != EXEC_SELFALSE ))
  1068. {
  1069. #if PROG_ERRORS
  1070. sprintf( bwb_ebuf, "in bwb_endselect(): END SELECT without SELECT" );
  1071. bwb_error( bwb_ebuf );
  1072. #else
  1073. bwb_error( err_syntax );
  1074. #endif
  1075. }
  1076. bwb_decexec();
  1077. #if MULTISEG_LINES
  1078. adv_eos( l->buffer, &( l->position ));
  1079. #endif
  1080. return bwb_zline( l );
  1081. }
  1082. #endif /* STRUCT_CMDS */
  1083. #if COMMON_CMDS || STRUCT_CMDS
  1084. /*** WHILE-WEND ***/
  1085. /***************************************************************
  1086. FUNCTION: bwb_while()
  1087. DESCRIPTION: This function handles the BASIC WHILE
  1088. statement and also the ANSI DO WHILE
  1089. statement.
  1090. SYNTAX: WHILE expression
  1091. DO WHILE expression
  1092. ***************************************************************/
  1093. #if ANSI_C
  1094. struct bwb_line *
  1095. bwb_while( struct bwb_line *l )
  1096. #else
  1097. struct bwb_line *
  1098. bwb_while( l )
  1099. struct bwb_line *l;
  1100. #endif
  1101. {
  1102. struct exp_ese *e;
  1103. struct bwb_line *r;
  1104. /* call bwb_exp() to interpret the expression */
  1105. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  1106. if ( (int) exp_getnval( e ) == TRUE )
  1107. {
  1108. /* if this is the first time at this WHILE statement, note it */
  1109. if ( CURTASK excs[ CURTASK exsc ].while_line != l )
  1110. {
  1111. bwb_incexec();
  1112. CURTASK excs[ CURTASK exsc ].while_line = l;
  1113. /* find the WEND statement (or LOOP statement) */
  1114. #if STRUCT_CMDS
  1115. if ( l->cmdnum == getcmdnum( CMD_DO ))
  1116. {
  1117. CURTASK excs[ CURTASK exsc ].wend_line = find_loop( l );
  1118. }
  1119. else
  1120. {
  1121. CURTASK excs[ CURTASK exsc ].wend_line = find_wend( l );
  1122. }
  1123. #else
  1124. CURTASK excs[ CURTASK exsc ].wend_line = find_wend( l );
  1125. #endif
  1126. if ( CURTASK excs[ CURTASK exsc ].wend_line == NULL )
  1127. {
  1128. return bwb_zline( l );
  1129. }
  1130. #if INTENSIVE_DEBUG
  1131. sprintf( bwb_ebuf, "in bwb_while(): initialize WHILE loop, line <%d>",
  1132. l->number );
  1133. bwb_debug( bwb_ebuf );
  1134. #endif
  1135. }
  1136. #if INTENSIVE_DEBUG
  1137. else
  1138. {
  1139. sprintf( bwb_ebuf, "in bwb_while(): return to WHILE loop, line <%d>",
  1140. l->number );
  1141. bwb_debug( bwb_ebuf );
  1142. }
  1143. #endif
  1144. bwb_setexec( l, l->position, EXEC_WHILE );
  1145. return bwb_zline( l );
  1146. }
  1147. else
  1148. {
  1149. CURTASK excs[ CURTASK exsc ].while_line = NULL;
  1150. r = CURTASK excs[ CURTASK exsc ].wend_line;
  1151. bwb_setexec( r, 0, CURTASK excs[ CURTASK exsc - 1 ].code );
  1152. r->position = 0;
  1153. bwb_decexec();
  1154. return r;
  1155. }
  1156. }
  1157. /***************************************************************
  1158. FUNCTION: bwb_wend()
  1159. DESCRIPTION: This function handles the BASIC WEND
  1160. statement and the LOOP statement ending
  1161. a DO WHILE loop.
  1162. SYNTAX: WEND
  1163. LOOP
  1164. ***************************************************************/
  1165. #if ANSI_C
  1166. struct bwb_line *
  1167. bwb_wend( struct bwb_line *l )
  1168. #else
  1169. struct bwb_line *
  1170. bwb_wend( l )
  1171. struct bwb_line *l;
  1172. #endif
  1173. {
  1174. /* check integrity of WHILE loop */
  1175. if ( CURTASK excs[ CURTASK exsc ].code != EXEC_WHILE )
  1176. {
  1177. #if PROG_ERRORS
  1178. sprintf( bwb_ebuf, "in bwb_wend(): exec stack code != EXEC_WHILE" );
  1179. bwb_error( bwb_ebuf );
  1180. #else
  1181. bwb_error( err_syntax );
  1182. #endif
  1183. }
  1184. if ( CURTASK excs[ CURTASK exsc ].while_line == NULL )
  1185. {
  1186. #if PROG_ERRORS
  1187. sprintf( bwb_ebuf, "in bwb_wend(): exec stack while_line == NULL" );
  1188. bwb_error( bwb_ebuf );
  1189. #else
  1190. bwb_error( err_syntax );
  1191. #endif
  1192. }
  1193. /* reset to the top of the current WHILE loop */
  1194. #if INTENSIVE_DEBUG
  1195. sprintf( bwb_ebuf, "in bwb_wend() return to line <%d>",
  1196. CURTASK excs[ CURTASK exsc ].while_line->number );
  1197. bwb_debug( bwb_ebuf );
  1198. #endif
  1199. CURTASK excs[ CURTASK exsc ].while_line->position = 0;
  1200. bwb_setexec( CURTASK excs[ CURTASK exsc ].while_line, 0, EXEC_WHILE );
  1201. return CURTASK excs[ CURTASK exsc ].while_line;
  1202. }
  1203. /***************************************************************
  1204. FUNCTION: find_wend()
  1205. DESCRIPTION: This function searches for a line containing
  1206. a WEND statement corresponding to a previous
  1207. WHILE statement.
  1208. ***************************************************************/
  1209. #if ANSI_C
  1210. static struct bwb_line *
  1211. find_wend( struct bwb_line *l )
  1212. #else
  1213. static struct bwb_line *
  1214. find_wend( l )
  1215. struct bwb_line *l;
  1216. #endif
  1217. {
  1218. struct bwb_line *current;
  1219. register int w_level;
  1220. int position;
  1221. w_level = 1;
  1222. for ( current = l->next; current != &CURTASK bwb_end; current = current->next )
  1223. {
  1224. position = 0;
  1225. if ( current->marked != TRUE )
  1226. {
  1227. line_start( current->buffer, &position, &( current->lnpos ),
  1228. &( current->lnum ),
  1229. &( current->cmdpos ),
  1230. &( current->cmdnum ),
  1231. &( current->startpos ) );
  1232. }
  1233. current->position = current->startpos;
  1234. if ( current->cmdnum > -1 )
  1235. {
  1236. if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_while )
  1237. {
  1238. ++w_level;
  1239. #if INTENSIVE_DEBUG
  1240. sprintf( bwb_ebuf, "in find_wend(): found WHILE at line %d, level %d",
  1241. current->number, w_level );
  1242. bwb_debug( bwb_ebuf );
  1243. #endif
  1244. }
  1245. else if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_wend )
  1246. {
  1247. --w_level;
  1248. #if INTENSIVE_DEBUG
  1249. sprintf( bwb_ebuf, "in find_wend(): found WEND at line %d, level %d",
  1250. current->number, w_level );
  1251. bwb_debug( bwb_ebuf );
  1252. #endif
  1253. if ( w_level == 0 )
  1254. {
  1255. return current->next;
  1256. }
  1257. }
  1258. }
  1259. }
  1260. #if PROG_ERRORS
  1261. sprintf( bwb_ebuf, "in find_wend(): WHILE without WEND" );
  1262. bwb_error( bwb_ebuf );
  1263. #else
  1264. bwb_error( err_syntax );
  1265. #endif
  1266. return NULL;
  1267. }
  1268. #if STRUCT_CMDS
  1269. /***************************************************************
  1270. FUNCTION: find_loop()
  1271. DESCRIPTION: This function searches for a line containing
  1272. a LOOP statement corresponding to a previous
  1273. DO statement.
  1274. ***************************************************************/
  1275. #if ANSI_C
  1276. extern struct bwb_line *
  1277. find_loop( struct bwb_line *l )
  1278. #else
  1279. extern struct bwb_line *
  1280. find_loop( l )
  1281. struct bwb_line *l;
  1282. #endif
  1283. {
  1284. struct bwb_line *current;
  1285. register int w_level;
  1286. int position;
  1287. w_level = 1;
  1288. for ( current = l->next; current != &CURTASK bwb_end; current = current->next )
  1289. {
  1290. position = 0;
  1291. if ( current->marked != TRUE )
  1292. {
  1293. line_start( current->buffer, &position, &( current->lnpos ),
  1294. &( current->lnum ),
  1295. &( current->cmdpos ),
  1296. &( current->cmdnum ),
  1297. &( current->startpos ) );
  1298. }
  1299. current->position = current->startpos;
  1300. if ( current->cmdnum > -1 )
  1301. {
  1302. if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_do )
  1303. {
  1304. ++w_level;
  1305. #if INTENSIVE_DEBUG
  1306. sprintf( bwb_ebuf, "in find_loop(): found DO at line %d, level %d",
  1307. current->number, w_level );
  1308. bwb_debug( bwb_ebuf );
  1309. #endif
  1310. }
  1311. else if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_loop )
  1312. {
  1313. --w_level;
  1314. #if INTENSIVE_DEBUG
  1315. sprintf( bwb_ebuf, "in fnd_loop(): found LOOP at line %d, level %d",
  1316. current->number, w_level );
  1317. bwb_debug( bwb_ebuf );
  1318. #endif
  1319. if ( w_level == 0 )
  1320. {
  1321. return current->next;
  1322. }
  1323. }
  1324. }
  1325. }
  1326. #if PROG_ERRORS
  1327. sprintf( bwb_ebuf, "in find_loop(): DO without LOOP" );
  1328. bwb_error( bwb_ebuf );
  1329. #else
  1330. bwb_error( err_syntax );
  1331. #endif
  1332. return NULL;
  1333. }
  1334. #endif /* STRUCT_CMDS */
  1335. #endif /* COMMON_CMDS || STRUCT_CMDS */
  1336. /*** FOR-NEXT ***/
  1337. /***************************************************************
  1338. FUNCTION: bwb_for()
  1339. DESCRIPTION: This function handles the BASIC FOR
  1340. statement.
  1341. SYNTAX: FOR counter = start TO finish [STEP increment]
  1342. ***************************************************************/
  1343. #if ANSI_C
  1344. struct bwb_line *
  1345. bwb_for( struct bwb_line *l )
  1346. #else
  1347. struct bwb_line *
  1348. bwb_for( l )
  1349. struct bwb_line *l;
  1350. #endif
  1351. {
  1352. register int n;
  1353. int e, loop;
  1354. int to, step, p;
  1355. int for_step, for_target;
  1356. struct exp_ese *exp;
  1357. struct bwb_variable *v;
  1358. char tbuf[ MAXSTRINGSIZE + 1 ];
  1359. /* get the variable name */
  1360. exp_getvfname( &( l->buffer[ l->position ] ), tbuf );
  1361. l->position += strlen( tbuf );
  1362. v = var_find( tbuf );
  1363. #if INTENSIVE_DEBUG
  1364. sprintf( bwb_ebuf, "in bwb_for(): variable name <%s>.", v->name );
  1365. bwb_debug( bwb_ebuf );
  1366. #endif
  1367. /* at this point one should find an equals sign ('=') */
  1368. adv_ws( l->buffer, &( l->position ) );
  1369. if ( l->buffer[ l->position ] != '=' )
  1370. {
  1371. #if PROG_ERRORS
  1372. sprintf( bwb_ebuf, "in bwb_for(): failed to find equals sign, buf <%s>",
  1373. &( l->buffer[ l->position ] ) );
  1374. bwb_error( bwb_ebuf );
  1375. #else
  1376. bwb_error( err_syntax );
  1377. #endif
  1378. return bwb_zline( l );
  1379. }
  1380. else
  1381. {
  1382. ++( l->position );
  1383. }
  1384. /* Find the TO and STEP statements */
  1385. cnd_tostep( l->buffer, l->position, &to, &step );
  1386. /* if there is no TO statement, then an error has ocurred */
  1387. if ( to < 1 )
  1388. {
  1389. #if PROG_ERRORS
  1390. sprintf( bwb_ebuf, "FOR statement without TO" );
  1391. bwb_error( bwb_ebuf );
  1392. #else
  1393. bwb_error( err_syntax );
  1394. #endif
  1395. return bwb_zline( l );
  1396. }
  1397. /* copy initial value to buffer and evaluate it */
  1398. tbuf[ 0 ] = '\0';
  1399. p = 0;
  1400. for ( n = l->position; n < to; ++n )
  1401. {
  1402. tbuf[ p ] = l->buffer[ n ];
  1403. ++p;
  1404. ++l->position;
  1405. tbuf[ p ] = '\0';
  1406. }
  1407. #if INTENSIVE_DEBUG
  1408. sprintf( bwb_ebuf, "in bwb_for(): initial value string <%s>",
  1409. tbuf );
  1410. bwb_debug( bwb_ebuf );
  1411. #endif
  1412. p = 0;
  1413. exp = bwb_exp( tbuf, FALSE, &p );
  1414. var_setnval( v, exp_getnval( exp ) );
  1415. #if INTENSIVE_DEBUG
  1416. sprintf( bwb_ebuf, "in bwb_for(): initial value <%d> pos <%d>",
  1417. exp_getnval( exp ), l->position );
  1418. bwb_debug( bwb_ebuf );
  1419. #endif
  1420. /* copy target value to small buffer and evaluate it */
  1421. tbuf[ 0 ] = '\0';
  1422. p = 0;
  1423. l->position = to + 2;
  1424. if ( step < 1 )
  1425. {
  1426. e = strlen( l->buffer );
  1427. }
  1428. else
  1429. {
  1430. e = step - 1;
  1431. }
  1432. loop = TRUE;
  1433. n = l->position;
  1434. while( loop == TRUE )
  1435. {
  1436. tbuf[ p ] = l->buffer[ n ];
  1437. ++p;
  1438. ++l->position;
  1439. tbuf[ p ] = '\0';
  1440. if ( n >= e )
  1441. {
  1442. loop = FALSE;
  1443. }
  1444. ++n;
  1445. if ( l->buffer[ n ] == ':' )
  1446. {
  1447. loop = FALSE;
  1448. }
  1449. }
  1450. #if INTENSIVE_DEBUG
  1451. sprintf( bwb_ebuf, "in bwb_for(): target value string <%s>",
  1452. tbuf );
  1453. bwb_debug( bwb_ebuf );
  1454. #endif
  1455. p = 0;
  1456. exp = bwb_exp( tbuf, FALSE, &p );
  1457. for_target = (int) exp_getnval( exp );
  1458. #if INTENSIVE_DEBUG
  1459. sprintf( bwb_ebuf, "in bwb_for(): target value <%d> pos <%d>",
  1460. exp_getnval( exp ), l->position );
  1461. bwb_debug( bwb_ebuf );
  1462. #endif
  1463. /* If there is a STEP statement, copy it to a buffer
  1464. and evaluate it */
  1465. if ( step > 1 )
  1466. {
  1467. tbuf[ 0 ] = '\0';
  1468. p = 0;
  1469. l->position = step + 4;
  1470. for ( n = l->position; n < (int) strlen( l->buffer ); ++n )
  1471. {
  1472. tbuf[ p ] = l->buffer[ n ];
  1473. ++p;
  1474. ++l->position;
  1475. tbuf[ p ] = '\0';
  1476. }
  1477. #if INTENSIVE_DEBUG
  1478. sprintf( bwb_ebuf, "in bwb_for(): step value string <%s>",
  1479. tbuf );
  1480. bwb_debug( bwb_ebuf );
  1481. #endif
  1482. p = 0;
  1483. exp = bwb_exp( tbuf, FALSE, &p );
  1484. for_step = (int) exp_getnval( exp );
  1485. }
  1486. else
  1487. {
  1488. for_step = 1;
  1489. }
  1490. #if INTENSIVE_DEBUG
  1491. sprintf( bwb_ebuf, "in bwb_for(): step value <%d>",
  1492. for_step );
  1493. bwb_debug( bwb_ebuf );
  1494. #endif
  1495. /* set position in current line and increment EXEC counter */
  1496. /* bwb_setexec( l, l->position, EXEC_NORM ); */ /* WRONG */
  1497. bwb_incexec();
  1498. CURTASK excs[ CURTASK exsc ].local_variable = v;
  1499. CURTASK excs[ CURTASK exsc ].for_step = for_step;
  1500. CURTASK excs[ CURTASK exsc ].for_target = for_target;
  1501. /* set exit line to be used by EXIT FOR */
  1502. #if STRUCT_CMDS
  1503. CURTASK excs[ CURTASK exsc ].wend_line = find_next( l );
  1504. #endif
  1505. /* set top line and position to be used in multisegmented FOR-NEXT loop */
  1506. #if MULTISEG_LINES
  1507. CURTASK excs[ CURTASK exsc ].for_line = l;
  1508. CURTASK excs[ CURTASK exsc ].for_position = l->position;
  1509. #endif
  1510. #if INTENSIVE_DEBUG
  1511. sprintf( bwb_ebuf, "in bwb_for(): setting code to EXEC_FOR",
  1512. l->position );
  1513. bwb_debug( bwb_ebuf );
  1514. #endif
  1515. bwb_setexec( l, l->position, EXEC_FOR );
  1516. #if INTENSIVE_DEBUG
  1517. sprintf( bwb_ebuf, "in bwb_for(): ready to exit, position <%d>",
  1518. l->position );
  1519. bwb_debug( bwb_ebuf );
  1520. #endif
  1521. /* proceed with processing */
  1522. return bwb_zline( l );
  1523. }
  1524. /***************************************************************
  1525. FUNCTION: bwb_next()
  1526. DESCRIPTION: This function handles the BASIC NEXT
  1527. statement.
  1528. SYNTAX: NEXT counter
  1529. ***************************************************************/
  1530. #if ANSI_C
  1531. struct bwb_line *
  1532. bwb_next( struct bwb_line *l )
  1533. #else
  1534. struct bwb_line *
  1535. bwb_next( l )
  1536. struct bwb_line *l;
  1537. #endif
  1538. {
  1539. char tbuf[ MAXSTRINGSIZE + 1 ];
  1540. #if INTENSIVE_DEBUG
  1541. struct bwb_variable *v;
  1542. #endif
  1543. #if INTENSIVE_DEBUG
  1544. sprintf( bwb_ebuf, "in bwb_next(): entered function, cmdnum <%d> exsc level <%d> code <%d>",
  1545. l->cmdnum, CURTASK exsc, CURTASK excs[ CURTASK exsc ].code );
  1546. bwb_debug( bwb_ebuf );
  1547. #endif
  1548. /* Check the integrity of the FOR statement */
  1549. if ( CURTASK excs[ CURTASK exsc ].code != EXEC_FOR )
  1550. {
  1551. #if PROG_ERRORS
  1552. sprintf( bwb_ebuf, "in bwb_next(): NEXT without FOR; code is <%d> instead of <%d>",
  1553. CURTASK excs[ CURTASK exsc ].code, EXEC_FOR );
  1554. bwb_error( bwb_ebuf );
  1555. #else
  1556. bwb_error( err_syntax );
  1557. #endif
  1558. }
  1559. /* read the argument, if there is one */
  1560. #if MULTISEG_LINES /* not currently needed otherwise */
  1561. exp_getvfname( &( l->buffer[ l->position ] ), tbuf );
  1562. l->position += strlen( tbuf );
  1563. #if INTENSIVE_DEBUG
  1564. v = var_find( tbuf );
  1565. sprintf( bwb_ebuf, "in bwb_next(): variable name detected <%s>.", v->name );
  1566. bwb_debug( bwb_ebuf );
  1567. #endif
  1568. #endif
  1569. /* decrement or increment the value */
  1570. var_setnval( CURTASK excs[ CURTASK exsc ].local_variable,
  1571. var_getnval( CURTASK excs[ CURTASK exsc ].local_variable )
  1572. + (bnumber) CURTASK excs[ CURTASK exsc ].for_step );
  1573. /* check for completion of the loop */
  1574. if ( CURTASK excs[ CURTASK exsc ].for_step > 0 ) /* if step is positive */
  1575. {
  1576. if ( (int) var_getnval( CURTASK excs[ CURTASK exsc ].local_variable )
  1577. > CURTASK excs[ CURTASK exsc ].for_target )
  1578. {
  1579. bwb_decexec();
  1580. #if MULTISEG_LINES
  1581. bwb_setexec( l, l->position, CURTASK excs[ CURTASK exsc ].code );
  1582. #else
  1583. bwb_setexec( l->next, 0, CURTASK excs[ CURTASK exsc ].code );
  1584. #endif
  1585. #if INTENSIVE_DEBUG
  1586. sprintf( bwb_ebuf, "in bwb_next(): end of loop" );
  1587. bwb_debug( bwb_ebuf );
  1588. #endif
  1589. #ifdef OLD_WAY
  1590. l->next->position = 0;
  1591. return l->next;
  1592. #else
  1593. return bwb_zline( l );
  1594. #endif
  1595. }
  1596. }
  1597. else /* if step is negative */
  1598. {
  1599. if ( (int) var_getnval( CURTASK excs[ CURTASK exsc ].local_variable )
  1600. < CURTASK excs[ CURTASK exsc ].for_target )
  1601. {
  1602. bwb_decexec();
  1603. bwb_setexec( l->next, 0, CURTASK excs[ CURTASK exsc ].code );
  1604. #if INTENSIVE_DEBUG
  1605. sprintf( bwb_ebuf, "in bwb_next(): end of loop" );
  1606. bwb_debug( bwb_ebuf );
  1607. #endif
  1608. #ifdef OLD_WAY
  1609. l->next->position = 0;
  1610. return l->next;
  1611. #else
  1612. return bwb_zline( l );
  1613. #endif
  1614. }
  1615. }
  1616. /* Target not reached: return to the top of the FOR loop */
  1617. #if INTENSIVE_DEBUG
  1618. sprintf( bwb_ebuf, "in bwb_next(): resetting code to EXEC_FOR",
  1619. l->position );
  1620. bwb_debug( bwb_ebuf );
  1621. #endif
  1622. #if MULTISEG_LINES
  1623. CURTASK excs[ CURTASK exsc ].for_line->position
  1624. = CURTASK excs[ CURTASK exsc ].for_position;
  1625. bwb_setexec( CURTASK excs[ CURTASK exsc ].for_line,
  1626. CURTASK excs[ CURTASK exsc ].for_position, EXEC_FOR );
  1627. #else
  1628. bwb_setexec( CURTASK excs[ CURTASK exsc - 1 ].line,
  1629. CURTASK excs[ CURTASK exsc - 1 ].position, EXEC_FOR );
  1630. #endif
  1631. return CURTASK excs[ CURTASK exsc - 1 ].line;
  1632. }
  1633. #if STRUCT_CMDS
  1634. /***************************************************************
  1635. FUNCTION: bwb_exitfor()
  1636. DESCRIPTION: This function handles the BASIC EXIT
  1637. FOR statement. This is a structured
  1638. programming command compatible with ANSI
  1639. BASIC. It is called from the bwb_exit()
  1640. subroutine.
  1641. SYNTAX: EXIT FOR
  1642. ***************************************************************/
  1643. #if ANSI_C
  1644. struct bwb_line *
  1645. bwb_exitfor( struct bwb_line *l )
  1646. #else
  1647. struct bwb_line *
  1648. bwb_exitfor( l )
  1649. struct bwb_line *l;
  1650. #endif
  1651. {
  1652. struct bwb_line *next_line;
  1653. int found;
  1654. register int level;
  1655. #if INTENSIVE_DEBUG
  1656. sprintf( bwb_ebuf, "in bwb_exitfor(): entered subroutine" );
  1657. bwb_debug( bwb_ebuf );
  1658. #endif
  1659. /* Check the integrity of the FOR statement */
  1660. found = FALSE;
  1661. level = CURTASK exsc;
  1662. do
  1663. {
  1664. if ( CURTASK excs[ level ].code == EXEC_FOR )
  1665. {
  1666. next_line = CURTASK excs[ CURTASK level ].wend_line;
  1667. found = TRUE;
  1668. }
  1669. else
  1670. {
  1671. --level;
  1672. }
  1673. }
  1674. while ( ( level >= 0 ) && ( found == FALSE ) );
  1675. if ( found != TRUE )
  1676. {
  1677. #if PROG_ERRORS
  1678. sprintf( bwb_ebuf, "in bwb_exitfor(): EXIT FOR without FOR" );
  1679. bwb_error( bwb_ebuf );
  1680. #else
  1681. bwb_error( err_syntax );
  1682. #endif
  1683. return bwb_zline( l );
  1684. }
  1685. #if INTENSIVE_DEBUG
  1686. sprintf( bwb_ebuf, "in bwb_exitfor(): level found is <%d>, current <%d>",
  1687. level, CURTASK exsc );
  1688. bwb_debug( bwb_ebuf );
  1689. #endif
  1690. /* decrement below the level of the NEXT statement */
  1691. while( CURTASK exsc >= level )
  1692. {
  1693. bwb_decexec();
  1694. }
  1695. /* set the next line in the exec stack */
  1696. next_line->position = 0;
  1697. bwb_setexec( next_line, 0, EXEC_NORM );
  1698. return next_line;
  1699. }
  1700. /***************************************************************
  1701. FUNCTION: find_next()
  1702. DESCRIPTION: This function searches for a line containing
  1703. a NEXT statement corresponding to a previous
  1704. FOR statement.
  1705. ***************************************************************/
  1706. #if ANSI_C
  1707. static struct bwb_line *
  1708. find_next( struct bwb_line *l )
  1709. #else
  1710. static struct bwb_line *
  1711. find_next( l )
  1712. struct bwb_line *l;
  1713. #endif
  1714. {
  1715. struct bwb_line *current;
  1716. register int w_level;
  1717. int position;
  1718. w_level = 1;
  1719. for ( current = l->next; current != &CURTASK bwb_end; current = current->next )
  1720. {
  1721. position = 0;
  1722. if ( current->marked != TRUE )
  1723. {
  1724. line_start( current->buffer, &position, &( current->lnpos ),
  1725. &( current->lnum ),
  1726. &( current->cmdpos ),
  1727. &( current->cmdnum ),
  1728. &( current->startpos ) );
  1729. }
  1730. current->position = current->startpos;
  1731. if ( current->cmdnum > -1 )
  1732. {
  1733. if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_for )
  1734. {
  1735. ++w_level;
  1736. #if INTENSIVE_DEBUG
  1737. sprintf( bwb_ebuf, "in find_next(): found FOR at line %d, level %d",
  1738. current->number, w_level );
  1739. bwb_debug( bwb_ebuf );
  1740. #endif
  1741. }
  1742. else if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_next )
  1743. {
  1744. --w_level;
  1745. #if INTENSIVE_DEBUG
  1746. sprintf( bwb_ebuf, "in find_next(): found NEXT at line %d, level %d",
  1747. current->number, w_level );
  1748. bwb_debug( bwb_ebuf );
  1749. #endif
  1750. if ( w_level == 0 )
  1751. {
  1752. #if INTENSIVE_DEBUG
  1753. sprintf( bwb_ebuf, "in find_next(): found returning line <%d>",
  1754. current->next->number );
  1755. bwb_debug( bwb_ebuf );
  1756. #endif
  1757. return current->next;
  1758. }
  1759. }
  1760. }
  1761. }
  1762. #if PROG_ERRORS
  1763. sprintf( bwb_ebuf, "FOR without NEXT" );
  1764. bwb_error( bwb_ebuf );
  1765. #else
  1766. bwb_error( err_syntax );
  1767. #endif
  1768. return NULL;
  1769. }
  1770. #endif /* STRUCT_CMDS for EXIT FOR */
  1771. /***************************************************************
  1772. FUNCTION: cnd_tostep()
  1773. DESCRIPTION: This function searches through the
  1774. <buffer> beginning at point <position>
  1775. and attempts to find positions of TO
  1776. and STEP statements.
  1777. ***************************************************************/
  1778. #if ANSI_C
  1779. static int
  1780. cnd_tostep( char *buffer, int position, int *to, int *step )
  1781. #else
  1782. static int
  1783. cnd_tostep( buffer, position, to, step )
  1784. char *buffer;
  1785. int position;
  1786. int *to;
  1787. int *step;
  1788. #endif
  1789. {
  1790. int loop, t_pos, b_pos, p_word;
  1791. char tbuf[ MAXSTRINGSIZE + 1 ];
  1792. /* set then and els to FALSE initially */
  1793. *to = *step = FALSE;
  1794. /* loop to find words */
  1795. p_word = b_pos = position;
  1796. t_pos = 0;
  1797. tbuf[ 0 ] = '\0';
  1798. loop = TRUE;
  1799. while ( loop == TRUE )
  1800. {
  1801. switch( buffer[ b_pos ] )
  1802. {
  1803. case '\0': /* end of string */
  1804. case ':': /* end of line segment */
  1805. return TRUE;
  1806. case ' ': /* whitespace = end of word */
  1807. case '\t':
  1808. #if INTENSIVE_DEBUG
  1809. sprintf( bwb_ebuf, "in cnd_tostep(): word is <%s>", tbuf );
  1810. bwb_debug( bwb_ebuf );
  1811. #endif
  1812. if ( strncmp( tbuf, CMD_TO, (size_t) strlen( CMD_TO ) ) == 0 )
  1813. {
  1814. #if INTENSIVE_DEBUG
  1815. sprintf( bwb_ebuf, "in cnd_tostep(): TO found at position <%d>.",
  1816. p_word );
  1817. bwb_debug( bwb_ebuf );
  1818. #endif
  1819. *to = p_word;
  1820. }
  1821. else if ( strncmp( tbuf, CMD_STEP, (size_t) strlen( CMD_STEP ) ) == 0 )
  1822. {
  1823. #if INTENSIVE_DEBUG
  1824. sprintf( bwb_ebuf, "in cnd_tostep(): STEP found at position <%d>.",
  1825. p_word );
  1826. bwb_debug( bwb_ebuf );
  1827. #endif
  1828. *step = p_word;
  1829. }
  1830. ++b_pos;
  1831. p_word = b_pos;
  1832. t_pos = 0;
  1833. tbuf[ 0 ] = '\0';
  1834. break;
  1835. default:
  1836. if ( islower( buffer[ b_pos ] ) != FALSE )
  1837. {
  1838. tbuf[ t_pos ] = (char) toupper( buffer[ b_pos ] );
  1839. }
  1840. else
  1841. {
  1842. tbuf[ t_pos ] = buffer[ b_pos ];
  1843. }
  1844. ++b_pos;
  1845. ++t_pos;
  1846. tbuf[ t_pos ] = '\0';
  1847. break;
  1848. }
  1849. }
  1850. return TRUE;
  1851. }
  1852. /***************************************************************
  1853. FUNCTION: var_setnval()
  1854. DESCRIPTION: This function sets the value of numerical
  1855. variable v to the value of i.
  1856. ***************************************************************/
  1857. #if ANSI_C
  1858. extern int
  1859. var_setnval( struct bwb_variable *v, bnumber i )
  1860. #else
  1861. int
  1862. var_setnval( v, i )
  1863. struct bwb_variable *v;
  1864. bnumber i;
  1865. #endif
  1866. {
  1867. switch( v->type )
  1868. {
  1869. case NUMBER:
  1870. * var_findnval( v, v->array_pos ) = i;
  1871. break;
  1872. default:
  1873. #if INTENSIVE_DEBUG
  1874. sprintf( bwb_ebuf, "in var_setnval(): variable <%s> is not a number",
  1875. v->name );
  1876. bwb_error( bwb_ebuf );
  1877. #else
  1878. bwb_error( err_mismatch );
  1879. #endif
  1880. }
  1881. /* successful assignment */
  1882. return TRUE;
  1883. }
  1884.