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.
 
 
 
 
 
 

2278 lines
51 KiB

  1. /***************************************************************
  2. bwb_stc.c Commands Related to Structured Programming
  3. for Bywater BASIC Interpreter
  4. Commands: CALL
  5. SUB
  6. FUNCTION
  7. END SUB
  8. END FUNCTION
  9. Copyright (c) 1993, Ted A. Campbell
  10. Bywater Software
  11. email: tcamp@delphi.com
  12. Copyright and Permissions Information:
  13. All U.S. and international rights are claimed by the author,
  14. Ted A. Campbell.
  15. This software is released under the terms of the GNU General
  16. Public License (GPL), which is distributed with this software
  17. in the file "COPYING". The GPL specifies the terms under
  18. which users may copy and use the software in this distribution.
  19. A separate license is available for commercial distribution,
  20. for information on which you should contact the author.
  21. ***************************************************************/
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include "bwbasic.h"
  25. #include "bwb_mes.h"
  26. /* prototypes */
  27. #if ANSI_C
  28. static int fslt_clear( void );
  29. static int fslt_add( struct bwb_line *line, int *position, int code );
  30. static struct bwb_line *fslt_findl( char *buffer );
  31. static struct fslte *fslt_findf( char *buffer );
  32. static int scan_getcmd( struct bwb_line *line, int *position );
  33. static int scan_readargs( struct fslte *f,
  34. struct bwb_line *line, int *position );
  35. static int call_readargs( struct fslte *f,
  36. char *expression, int *position );
  37. static int is_endsub( struct bwb_line *l );
  38. static struct bwb_line *find_endsub( struct bwb_line *l );
  39. static struct bwb_line *bwb_loopuntil( struct bwb_line *l );
  40. struct bwb_variable *bwb_vtov( struct bwb_variable *dst, struct bwb_variable *src );
  41. struct bwb_variable *bwb_etov( struct bwb_variable *dst, struct exp_ese *src );
  42. struct bwb_variable *var_pos( struct bwb_variable *firstvar, int p );
  43. int fslt_addcallvar( struct bwb_variable *v );
  44. int fslt_addlocalvar( struct fslte *f, struct bwb_variable *v );
  45. #else
  46. static int fslt_clear();
  47. static int fslt_add();
  48. static struct bwb_line *fslt_findl();
  49. static struct fslte *fslt_findf();
  50. static int scan_getcmd();
  51. static int scan_readargs();
  52. static int call_readargs();
  53. static int is_endsub();
  54. static struct bwb_line *find_endsub();
  55. static struct bwb_line *bwb_loopuntil();
  56. struct bwb_variable *bwb_vtov();
  57. struct bwb_variable *bwb_etov();
  58. struct bwb_variable *var_pos();
  59. int fslt_addcallvar();
  60. int fslt_addlocalvar();
  61. #endif /* ANSI_C for prototypes */
  62. /***************************************************************
  63. FUNCTION: bwb_scan()
  64. DESCRIPTION: This function scans all lines of the
  65. program in memory and creates a FUNCTION-
  66. SUB lookup table (fslt) for the program.
  67. ***************************************************************/
  68. #if ANSI_C
  69. int
  70. bwb_scan( void )
  71. #else
  72. int
  73. bwb_scan()
  74. #endif
  75. {
  76. struct bwb_line *current;
  77. int position;
  78. int c;
  79. #if PROG_ERRORS
  80. if ( CURTASK rescan != TRUE )
  81. {
  82. bwb_error( "in bwb_scan(): call to scan while CURTASK rescan != TRUE" );
  83. return FALSE;
  84. }
  85. #endif
  86. #if INTENSIVE_DEBUG
  87. sprintf( bwb_ebuf, "in bwb_scan(): beginning scan..." );
  88. bwb_debug( bwb_ebuf );
  89. #endif
  90. /* first run through the FUNCTION - SUB loopkup table
  91. and free any existing memory */
  92. fslt_clear();
  93. /* run through the list of lines and identify SUB and FUNCTION statements */
  94. for ( current = CURTASK bwb_start.next; current != &CURTASK bwb_end; current = current->next )
  95. {
  96. #if INTENSIVE_DEBUG
  97. sprintf( bwb_ebuf, "in bwb_scan(): scanning line <%d>", current->number );
  98. bwb_debug( bwb_ebuf );
  99. #endif
  100. c = scan_getcmd( current, &position );
  101. if ( c == getcmdnum( CMD_SUB ))
  102. {
  103. fslt_add( current, &position, EXEC_CALLSUB );
  104. }
  105. else if ( c == getcmdnum( CMD_FUNCTION ))
  106. {
  107. fslt_add( current, &position, EXEC_FUNCTION );
  108. }
  109. else if ( c == getcmdnum( CMD_DEF ))
  110. {
  111. fslt_add( current, &position, EXEC_FUNCTION );
  112. }
  113. #if STRUCT_CMDS
  114. else if ( c == getcmdnum( CMD_LABEL ))
  115. {
  116. fslt_add( current, &position, EXEC_LABEL );
  117. }
  118. #endif
  119. }
  120. /* return */
  121. CURTASK rescan = FALSE;
  122. return TRUE;
  123. }
  124. /***************************************************************
  125. FUNCTION: fslt_clear()
  126. DESCRIPTION: This C function clears all existing memory
  127. in the FUNCTION-SUB lookup table.
  128. ***************************************************************/
  129. #if ANSI_C
  130. static int
  131. fslt_clear( void )
  132. #else
  133. static int
  134. fslt_clear()
  135. #endif
  136. {
  137. struct fslte *current, *next;
  138. struct bwb_variable *c, *n;
  139. /* run through table and clear memory */
  140. next = CURTASK fslt_start.next;
  141. for ( current = CURTASK fslt_start.next; current != &CURTASK fslt_end;
  142. current = next )
  143. {
  144. /* check for local variables and free them */
  145. c = current->local_variable;
  146. while ( c != NULL )
  147. {
  148. n = c->next;
  149. free( c );
  150. c = n;
  151. }
  152. next = current->next;
  153. free( current );
  154. }
  155. /* reset linkage */
  156. CURTASK fslt_start.next = &CURTASK fslt_end;
  157. return TRUE;
  158. }
  159. /***************************************************************
  160. FUNCTION: scan_getcmd()
  161. DESCRIPTION: This command returns the command number
  162. for the first BASIC command word encountered
  163. in a line.
  164. ***************************************************************/
  165. #if ANSI_C
  166. static int
  167. scan_getcmd( struct bwb_line *line, int *position )
  168. #else
  169. static int
  170. scan_getcmd( line, position )
  171. struct bwb_line *line;
  172. int *position;
  173. #endif
  174. {
  175. char tbuf[ MAXSTRINGSIZE + 1 ];
  176. *position = 0;
  177. adv_ws( line->buffer, position );
  178. /* check for NULL line */
  179. if ( line->buffer[ *position ] == '\0' )
  180. {
  181. return -1;
  182. }
  183. /* check for line number and advance beyond it */
  184. if ( isdigit( line->buffer[ *position ] ))
  185. {
  186. scan_element( line->buffer, position, tbuf );
  187. }
  188. /* get the command element in the buffer */
  189. scan_element( line->buffer, position, tbuf );
  190. #if INTENSIVE_DEBUG
  191. sprintf( bwb_ebuf, "in scan_getcmd(): scanning element <%s>", tbuf );
  192. bwb_debug( bwb_ebuf );
  193. #endif
  194. #if STRUCT_CMDS
  195. if ( is_label( tbuf ) == TRUE )
  196. {
  197. #if INTENSIVE_DEBUG
  198. sprintf( bwb_ebuf, "in scan_getcmd(): found label <%s>", tbuf );
  199. bwb_debug( bwb_ebuf );
  200. #endif
  201. return getcmdnum( CMD_LABEL );
  202. }
  203. #endif
  204. bwb_strtoupper( tbuf );
  205. /* return command number */
  206. return getcmdnum( tbuf );
  207. }
  208. /***************************************************************
  209. FUNCTION: scan_element()
  210. DESCRIPTION: This function reads characters in <buffer>
  211. beginning at <pos> and advances past a
  212. line element, incrementing <pos> appropri-
  213. ately and returning the line element in
  214. <element>.
  215. This function is almost identical to adv_element(),
  216. but it will not stop at a full colon. This is
  217. necessary to detect a label in the first element
  218. position. If MULTISEG_LINES is defined as TRUE,
  219. adv_element() will stop at the colon, interpreting
  220. it as the end-of-segment marker.
  221. ***************************************************************/
  222. #if ANSI_C
  223. extern int
  224. scan_element( char *buffer, int *pos, char *element )
  225. #else
  226. int
  227. scan_element( buffer, pos, element )
  228. char *buffer;
  229. int *pos;
  230. char *element;
  231. #endif
  232. {
  233. int loop; /* control loop */
  234. int e_pos; /* position in element buffer */
  235. int str_const; /* boolean: building a string constant */
  236. /* advance beyond any initial whitespace */
  237. adv_ws( buffer, pos );
  238. #if INTENSIVE_DEBUG
  239. sprintf( bwb_ebuf, "in adv_element(): receieved <%s>.", &( buffer[ *pos ] ));
  240. bwb_debug( bwb_ebuf );
  241. #endif
  242. /* now loop while building an element and looking for an
  243. element terminator */
  244. loop = TRUE;
  245. e_pos = 0;
  246. element[ e_pos ] = '\0';
  247. str_const = FALSE;
  248. while ( loop == TRUE )
  249. {
  250. switch( buffer[ *pos ] )
  251. {
  252. case ',': /* element terminators */
  253. case ';':
  254. case '=':
  255. case ' ':
  256. case '\t':
  257. case '\0':
  258. case '\n':
  259. case '\r':
  260. if ( str_const == TRUE )
  261. {
  262. element[ e_pos ] = buffer[ *pos ];
  263. ++e_pos;
  264. ++( *pos );
  265. element[ e_pos ] = '\0';
  266. }
  267. else
  268. {
  269. return TRUE;
  270. }
  271. break;
  272. case '\"': /* string constant */
  273. element[ e_pos ] = buffer[ *pos ];
  274. ++e_pos;
  275. ++( *pos );
  276. element[ e_pos ] = '\0';
  277. if ( str_const == TRUE ) /* termination of string constant */
  278. {
  279. return TRUE;
  280. }
  281. else /* beginning of string constant */
  282. {
  283. str_const = TRUE;
  284. }
  285. break;
  286. default:
  287. element[ e_pos ] = buffer[ *pos ];
  288. ++e_pos;
  289. ++( *pos );
  290. element[ e_pos ] = '\0';
  291. break;
  292. }
  293. }
  294. /* This should not happen */
  295. return FALSE;
  296. }
  297. /***************************************************************
  298. FUNCTION: fslt_add()
  299. DESCRIPTION: This C function adds an entry to the
  300. FUNCTION-SUB lookup table.
  301. ***************************************************************/
  302. #if ANSI_C
  303. static int
  304. fslt_add( struct bwb_line *line, int *position, int code )
  305. #else
  306. static int
  307. fslt_add( line, position, code )
  308. struct bwb_line *line;
  309. int *position;
  310. int code;
  311. #endif
  312. {
  313. char tbuf[ MAXSTRINGSIZE + 1 ];
  314. char *name;
  315. struct bwb_variable *v;
  316. struct fslte *f, *n;
  317. int p;
  318. /* get the element for name */
  319. if ( code == EXEC_LABEL )
  320. {
  321. p = 0;
  322. scan_element( line->buffer, &p, tbuf );
  323. if ( isdigit( tbuf[ 0 ] ))
  324. {
  325. scan_element( line->buffer, &p, tbuf );
  326. }
  327. tbuf[ strlen( tbuf ) - 1 ] = '\0';
  328. }
  329. else
  330. {
  331. adv_ws( line->buffer, position );
  332. exp_getvfname( &( line->buffer[ *position ] ), tbuf );
  333. *position += strlen( tbuf );
  334. }
  335. #if INTENSIVE_DEBUG
  336. sprintf( bwb_ebuf, "in fslt_add(): adding SUB/FUNCTION/LABEL code <%d> name <%s>",
  337. code, tbuf );
  338. bwb_debug( bwb_ebuf );
  339. #endif
  340. /* get memory for name buffer */
  341. if ( ( name = calloc( 1, strlen( tbuf ) + 1 ) ) == NULL )
  342. {
  343. #if PROG_ERRORS
  344. bwb_error( "in fslt_add(): failed to get memory for name buffer" );
  345. #else
  346. bwb_error( err_getmem );
  347. #endif
  348. return FALSE;
  349. }
  350. strcpy( name, tbuf );
  351. /* get memory for fslt structure */
  352. if ( ( f = calloc( 1, sizeof( struct fslte ) ) ) == NULL )
  353. {
  354. #if PROG_ERRORS
  355. bwb_error( "in fslt_add(): failed to get memory for fslt structure" );
  356. #else
  357. bwb_error( err_getmem );
  358. #endif
  359. return FALSE;
  360. }
  361. /* fill in structure */
  362. f->line = line;
  363. f->name = name;
  364. f->code = code;
  365. f->local_variable = NULL;
  366. #if INTENSIVE_DEBUG
  367. sprintf( bwb_ebuf, "in fslt_add(): current buffer <%s>",
  368. &( line->buffer[ *position ] ) );
  369. bwb_debug( bwb_ebuf );
  370. #endif
  371. /* read arguments */
  372. adv_ws( line->buffer, position );
  373. if ( line->buffer[ *position ] == '(' )
  374. {
  375. scan_readargs( f, line, position );
  376. }
  377. /* if function, add one more local variable expressing the name
  378. of the function */
  379. if ( code == EXEC_FUNCTION )
  380. {
  381. v = var_new( tbuf );
  382. fslt_addlocalvar( f, v );
  383. #if INTENSIVE_DEBUG
  384. sprintf( bwb_ebuf, "in fslt_add(): added function-name variable <%s>",
  385. v->name );
  386. bwb_debug( bwb_ebuf );
  387. getchar();
  388. #endif
  389. }
  390. /* establish linkages */
  391. n = CURTASK fslt_start.next;
  392. CURTASK fslt_start.next = f;
  393. f->next = n;
  394. return TRUE;
  395. }
  396. /***************************************************************
  397. FUNCTION: scan_readargs()
  398. DESCRIPTION: This C function reads arguments (variable
  399. names for an entry added to the FUNCTION-
  400. SUB lookup table.
  401. ***************************************************************/
  402. #if ANSI_C
  403. static int
  404. scan_readargs( struct fslte *f, struct bwb_line *line, int *position )
  405. #else
  406. static int
  407. scan_readargs( f, line, position )
  408. struct fslte *f;
  409. struct bwb_line *line;
  410. int *position;
  411. #endif
  412. {
  413. int control_loop;
  414. struct bwb_variable *v;
  415. char tbuf[ MAXSTRINGSIZE + 1 ];
  416. #if INTENSIVE_DEBUG
  417. sprintf( bwb_ebuf, "in scan_readargs(): reading arguments, buffer <%s>",
  418. &( line->buffer[ *position ] ) );
  419. bwb_debug( bwb_ebuf );
  420. #endif
  421. /* if we are at begin paren, advance */
  422. if ( line->buffer[ *position ] == '(' )
  423. {
  424. ++( *position );
  425. }
  426. /* loop through looking for arguments */
  427. control_loop = TRUE;
  428. adv_ws( line->buffer, position );
  429. while ( control_loop == TRUE )
  430. {
  431. switch( line->buffer[ *position ] )
  432. {
  433. case '\n': /* premature end of line */
  434. case '\r':
  435. case '\0':
  436. control_loop = FALSE;
  437. f->startpos = *position;
  438. bwb_error( err_syntax );
  439. return FALSE;
  440. case ')': /* end of argument list */
  441. ++( *position );
  442. control_loop = FALSE;
  443. f->startpos = *position;
  444. return TRUE;
  445. default: /* presume beginning of argument == variable name */
  446. exp_getvfname( &( line->buffer[ *position ] ), tbuf );
  447. *position += strlen( tbuf );
  448. #if INTENSIVE_DEBUG
  449. sprintf( bwb_ebuf, "in scan_readargs(): read argument <%s>",
  450. tbuf );
  451. bwb_debug( bwb_ebuf );
  452. #endif
  453. /* initialize the variable and add it to local chain */
  454. v = var_new( tbuf );
  455. fslt_addlocalvar( f, v );
  456. /* advance past the comma */
  457. if ( line->buffer[ *position ] == ',' )
  458. {
  459. ++( *position );
  460. }
  461. break;
  462. }
  463. adv_ws( line->buffer, position );
  464. }
  465. return TRUE;
  466. }
  467. /***************************************************************
  468. FUNCTION: call_readargs()
  469. DESCRIPTION: This C function reads arguments (variable
  470. names for a subroutine CALL or function
  471. call.
  472. ***************************************************************/
  473. #if ANSI_C
  474. static int
  475. call_readargs( struct fslte *f, char *expression, int *position )
  476. #else
  477. static int
  478. call_readargs( f, expression, position )
  479. struct fslte *f;
  480. char *expression;
  481. int *position;
  482. #endif
  483. {
  484. int control_loop;
  485. struct bwb_variable *v, *c;
  486. char tbuf[ MAXSTRINGSIZE + 1 ];
  487. int argument_counter;
  488. int local_pos, single_var;
  489. struct exp_ese *e;
  490. #if INTENSIVE_DEBUG
  491. sprintf( bwb_ebuf, "in call_readargs(): reading arguments, buffer <%s>",
  492. &( expression[ *position ] ) );
  493. bwb_debug( bwb_ebuf );
  494. #endif
  495. /* if we are at begin paren, advance */
  496. if ( expression[ *position ] == '(' )
  497. {
  498. ++( *position );
  499. }
  500. /* loop through looking for arguments */
  501. control_loop = TRUE;
  502. argument_counter = 0;
  503. while ( control_loop == TRUE )
  504. {
  505. adv_ws( expression, position );
  506. #if INTENSIVE_DEBUG
  507. sprintf( bwb_ebuf, "in call_readargs(): in loop, buffer <%s>",
  508. &( expression[ *position ] ) );
  509. bwb_debug( bwb_ebuf );
  510. #endif
  511. switch( expression[ *position ] )
  512. {
  513. case '\n': /* end of line */
  514. case '\r':
  515. case '\0':
  516. #if MULTISEG_LINES
  517. case ':': /* end of segment */
  518. #endif
  519. control_loop = FALSE;
  520. return FALSE;
  521. case ')': /* end of argument list */
  522. ++( *position );
  523. control_loop = FALSE;
  524. return TRUE;
  525. default: /* presume beginning of argument */
  526. /* read the first word to see if it is a single variable name */
  527. single_var = FALSE;
  528. exp_getvfname( &( expression[ *position ] ), tbuf );
  529. local_pos = *position + strlen( tbuf );
  530. adv_ws( expression, &local_pos );
  531. #if INTENSIVE_DEBUG
  532. sprintf( bwb_ebuf, "in call_readargs(): in loop, tbuf <%s>",
  533. tbuf );
  534. bwb_debug( bwb_ebuf );
  535. #endif
  536. /* check now for the single variable name */
  537. if ( strlen( tbuf ) == 0 )
  538. {
  539. single_var = FALSE;
  540. }
  541. else
  542. {
  543. switch ( expression[ local_pos ] )
  544. {
  545. case ')': /* end of argument list */
  546. #if INTENSIVE_DEBUG
  547. sprintf( bwb_ebuf, "in call_readargs(): detected end of argument list" );
  548. bwb_debug( bwb_ebuf );
  549. #endif
  550. ++local_pos; /* and fall through */
  551. case '\n': /* end of line */
  552. case '\r':
  553. case '\0':
  554. #if MULTISEG_LINES
  555. case ':': /* end of segment */
  556. #endif
  557. control_loop = FALSE; /* and fall through */
  558. /* added 1993-06-16 */
  559. case ',': /* end of argument */
  560. single_var = TRUE;
  561. /* look for variable from previous (calling) level */
  562. -- CURTASK exsc;
  563. v = var_find( tbuf ); /* find variable there */
  564. ++ CURTASK exsc;
  565. c = var_pos( CURTASK excs[ CURTASK exsc ].local_variable,
  566. argument_counter ); /* find local equivalent */
  567. bwb_vtov( c, v ); /* assign calling value to local variable */
  568. #if INTENSIVE_DEBUG
  569. sprintf( bwb_ebuf, "in call_readargs(): variable name is <%s>, local name <%s>",
  570. v->name, c->name );
  571. bwb_debug( bwb_ebuf );
  572. #endif
  573. *position = local_pos;
  574. break;
  575. default:
  576. single_var = FALSE;
  577. break;
  578. }
  579. }
  580. if ( single_var == FALSE )
  581. {
  582. #if INTENSIVE_DEBUG
  583. sprintf( bwb_ebuf, "in call_readargs(): in loop, parse expression <%s>",
  584. &( expression[ *position ] ) );
  585. bwb_debug( bwb_ebuf );
  586. #endif
  587. e = bwb_exp( expression, FALSE, position ); /* parse */
  588. #if INTENSIVE_DEBUG
  589. sprintf( bwb_ebuf, "in call_readargs(): in loop, parsed expression, buffer <%s>",
  590. &( expression[ *position ] ) );
  591. bwb_debug( bwb_ebuf );
  592. #endif
  593. v = var_pos( CURTASK excs[ CURTASK exsc ].local_variable,
  594. argument_counter ); /* assign to variable */
  595. bwb_etov( v, e ); /* assign value */
  596. }
  597. /* add the variable to the calling variable chain */
  598. fslt_addcallvar( v );
  599. #if INTENSIVE_DEBUG
  600. str_btoc( tbuf, var_getsval( v ));
  601. if ( single_var == TRUE )
  602. {
  603. sprintf( bwb_ebuf, "in call_readargs(): added arg <%d> (single) name <%s> value <%s>",
  604. argument_counter, v->name, tbuf );
  605. }
  606. else
  607. {
  608. sprintf( bwb_ebuf, "in call_readargs(): added arg <%d> (expression) name <%s> value <%s>",
  609. argument_counter, v->name, tbuf );
  610. }
  611. bwb_debug( bwb_ebuf );
  612. getchar();
  613. #endif
  614. /* advance past comma if present */
  615. adv_ws( expression, position );
  616. if ( expression[ *position ] == ',' )
  617. {
  618. ++( *position );
  619. }
  620. break;
  621. }
  622. ++argument_counter;
  623. }
  624. #if INTENSIVE_DEBUG
  625. sprintf( bwb_ebuf, "in call_readargs(): exiting function" );
  626. bwb_debug( bwb_ebuf );
  627. #endif
  628. return TRUE;
  629. }
  630. /***************************************************************
  631. FUNCTION: fslt_findl()
  632. DESCRIPTION: This C function finds a line corresponding
  633. to a name in the FUNCTION-SUB lookup
  634. table.
  635. ***************************************************************/
  636. #if ANSI_C
  637. static struct bwb_line *
  638. fslt_findl( char *buffer )
  639. #else
  640. static struct bwb_line *
  641. fslt_findl( buffer )
  642. char *buffer;
  643. #endif
  644. {
  645. struct fslte *r;
  646. r = fslt_findf( buffer );
  647. return r->line;
  648. }
  649. /***************************************************************
  650. FUNCTION: fslt_findf()
  651. DESCRIPTION: This C function finds an fslte structure
  652. corresponding to a name in the FUNCTION-
  653. SUB lookup table.
  654. ***************************************************************/
  655. #if ANSI_C
  656. static struct fslte *
  657. fslt_findf( char *buffer )
  658. #else
  659. static struct fslte *
  660. fslt_findf( buffer )
  661. char *buffer;
  662. #endif
  663. {
  664. struct fslte *f;
  665. register int c;
  666. /* remove open-paren from string */
  667. for ( c = 0; buffer[ c ] != '\0'; ++c )
  668. {
  669. if ( buffer[ c ] == '(' )
  670. {
  671. buffer[ c ] = '\0';
  672. }
  673. }
  674. #if INTENSIVE_DEBUG
  675. sprintf( bwb_ebuf, "in fslt_findf(): search for name <%s>", buffer );
  676. bwb_debug( bwb_ebuf );
  677. #endif
  678. /* run through the table */
  679. for ( f = CURTASK fslt_start.next; f != &CURTASK fslt_end; f = f->next )
  680. {
  681. if ( strcmp( f->name, buffer ) == 0 )
  682. {
  683. return f;
  684. }
  685. }
  686. /* search has failed */
  687. #if PROG_ERRORS
  688. sprintf( bwb_ebuf, "in fslt_findf(): failed to find Function/Subroutine <%s>",
  689. buffer );
  690. bwb_error( bwb_ebuf );
  691. #else
  692. bwb_error( err_lnnotfound );
  693. #endif
  694. return NULL;
  695. }
  696. /***************************************************************
  697. FUNCTION: bwb_def()
  698. DESCRIPTION: This C function implements the BASIC
  699. DEF statement. Since DEF and FUNCTION
  700. are equivalent, it simply passes execution
  701. to bwb_function().
  702. SYNTAX: DEF FNname(arg...)] = expression
  703. NOTE: It is not a strict requirement that the
  704. function name should begin with "FN".
  705. ***************************************************************/
  706. #if ANSI_C
  707. struct bwb_line *
  708. bwb_def( struct bwb_line *l )
  709. #else
  710. struct bwb_line *
  711. bwb_def( l )
  712. struct bwb_line *l;
  713. #endif
  714. {
  715. #if MULTISEG_LINES
  716. adv_eos( l->buffer, &( l->position ));
  717. #endif
  718. return bwb_zline( l );
  719. }
  720. #if STRUCT_CMDS
  721. /***************************************************************
  722. FUNCTION: bwb_function()
  723. DESCRIPTION: This C function implements the BASIC
  724. FUNCTION and DEF commands.
  725. SYNTAX: FUNCTION function-definition
  726. ***************************************************************/
  727. #if ANSI_C
  728. struct bwb_line *
  729. bwb_function( struct bwb_line *l )
  730. #else
  731. struct bwb_line *
  732. bwb_function( l )
  733. struct bwb_line *l;
  734. #endif
  735. {
  736. return bwb_def( l );
  737. }
  738. /***************************************************************
  739. FUNCTION: bwb_endfnc()
  740. DESCRIPTION: This C function implements the BASIC
  741. END FUNCTION command, ending a subroutine
  742. definition. Because the command END
  743. can have multiple meanings, this function
  744. should be called from the bwb_xend()
  745. function, which should be able to identify
  746. an END FUNCTION command.
  747. SYNTAX: END FUNCTION
  748. ***************************************************************/
  749. #if ANSI_C
  750. struct bwb_line *
  751. bwb_endfnc( struct bwb_line *l )
  752. #else
  753. struct bwb_line *
  754. bwb_endfnc( l )
  755. struct bwb_line *l;
  756. #endif
  757. {
  758. struct bwb_variable *local;
  759. register int c;
  760. /* assign local variable values to calling variables */
  761. local = CURTASK excs[ CURTASK exsc ].local_variable;
  762. for ( c = 0; c < CURTASK excs[ CURTASK exsc ].n_cvs; ++c )
  763. {
  764. bwb_vtov( CURTASK excs[ CURTASK exsc ].calling_variable[ c ], local );
  765. local = local->next;
  766. }
  767. /* decrement the EXEC stack counter */
  768. bwb_decexec();
  769. /* and return next from old line */
  770. CURTASK excs[ CURTASK exsc ].line->next->position = 0;
  771. return CURTASK excs[ CURTASK exsc ].line->next;
  772. }
  773. /***************************************************************
  774. FUNCTION: bwb_call()
  775. DESCRIPTION: This C function implements the BASIC
  776. CALL subroutine command.
  777. SYNTAX: CALL subroutine-name
  778. ***************************************************************/
  779. #if ANSI_C
  780. struct bwb_line *
  781. bwb_call( struct bwb_line *l )
  782. #else
  783. struct bwb_line *
  784. bwb_call( l )
  785. struct bwb_line *l;
  786. #endif
  787. {
  788. char tbuf[ MAXSTRINGSIZE + 1 ];
  789. struct bwb_line *call_line;
  790. struct fslte *f;
  791. adv_element( l->buffer, &( l->position ), tbuf );
  792. #if INTENSIVE_DEBUG
  793. sprintf( bwb_ebuf, "in bwb_call(): call to subroutine <%s>", tbuf );
  794. bwb_debug( bwb_ebuf );
  795. #endif
  796. /* find the line to call */
  797. call_line = fslt_findl( tbuf );
  798. f = fslt_findf( tbuf );
  799. if ( call_line == NULL )
  800. {
  801. return bwb_zline( l );
  802. }
  803. #if INTENSIVE_DEBUG
  804. sprintf( bwb_ebuf, "in bwb_call(): found line <%s>",
  805. call_line->buffer );
  806. bwb_debug( bwb_ebuf );
  807. #endif
  808. /* save the old position on the EXEC stack */
  809. bwb_setexec( l, l->position, CURTASK excs[ CURTASK exsc ].code );
  810. /* increment and set new EXEC stack */
  811. bwb_incexec();
  812. call_line->position = 0;
  813. bwb_setexec( call_line, 0, EXEC_CALLSUB );
  814. /* attach local variables */
  815. CURTASK excs[ CURTASK exsc ].local_variable = f->local_variable;
  816. /* read calling variables for this call */
  817. call_readargs( f, l->buffer, &( l->position ) );
  818. return call_line;
  819. }
  820. /***************************************************************
  821. FUNCTION: bwb_sub()
  822. DESCRIPTION: This function implements the BASIC
  823. SUB command, introducing a named
  824. subroutine.
  825. SYNTAX: SUB subroutine-name
  826. (followed by subroutine definition ending
  827. with END SUB).
  828. ***************************************************************/
  829. #if ANSI_C
  830. struct bwb_line *
  831. bwb_sub( struct bwb_line *l )
  832. #else
  833. struct bwb_line *
  834. bwb_sub( l )
  835. struct bwb_line *l;
  836. #endif
  837. {
  838. char tbuf[ MAXSTRINGSIZE + 1 ];
  839. struct bwb_line *rline;
  840. #if MULTISEG_LINES
  841. struct fslte *f;
  842. #endif
  843. #if INTENSIVE_DEBUG
  844. sprintf( bwb_ebuf, "in bwb_sub(): entered function at exec level <%d>",
  845. CURTASK exsc );
  846. bwb_debug( bwb_ebuf );
  847. #endif
  848. /* check current exec level: if 1 then only MAIN should be executed */
  849. if ( CURTASK exsc == 0 )
  850. {
  851. adv_element( l->buffer, &( l->position ), tbuf );
  852. bwb_strtoupper( tbuf );
  853. if ( strcmp( tbuf, "MAIN" ) == 0 )
  854. {
  855. #if INTENSIVE_DEBUG
  856. sprintf( bwb_ebuf, "in bwb_sub(): found MAIN function at level 0" );
  857. bwb_debug( bwb_ebuf );
  858. #endif
  859. bwb_incexec();
  860. bwb_setexec( l->next, 0, EXEC_MAIN );
  861. return bwb_zline( l );
  862. }
  863. /* if a MAIN function was not found at level 0, then skip the subroutine */
  864. else
  865. {
  866. #if INTENSIVE_DEBUG
  867. sprintf( bwb_ebuf, "in bwb_sub(): found non-MAIN function at level 0" );
  868. bwb_debug( bwb_ebuf );
  869. #endif
  870. rline = find_endsub( l );
  871. bwb_setexec( rline->next, 0, EXEC_CALLSUB );
  872. rline->next->position = 0;
  873. return rline->next;
  874. }
  875. }
  876. /* check for integrity of CALL-SUB sequence if above level 0 */
  877. else if ( CURTASK excs[ CURTASK exsc ].code != EXEC_CALLSUB )
  878. {
  879. #if PROG_ERRORS
  880. sprintf( bwb_ebuf, "in bwb_sub(): SUB without CALL" );
  881. bwb_error( bwb_ebuf );
  882. #else
  883. bwb_error( err_retnogosub );
  884. #endif
  885. }
  886. /* advance position */
  887. #if MULTISEG_LINES
  888. adv_ws( l->buffer, &( l->position ));
  889. adv_element( l->buffer, &( l->position ), tbuf );
  890. f = fslt_findf( tbuf );
  891. l->position = f->startpos;
  892. return bwb_zline( l );
  893. #else
  894. return bwb_zline( l );
  895. #endif
  896. }
  897. /***************************************************************
  898. FUNCTION: find_endsub()
  899. DESCRIPTION: This function searches for a line containing
  900. an END SUB statement corresponding to a previous
  901. SUB statement.
  902. ***************************************************************/
  903. #if ANSI_C
  904. static struct bwb_line *
  905. find_endsub( struct bwb_line *l )
  906. #else
  907. static struct bwb_line *
  908. find_endsub( l )
  909. struct bwb_line *l;
  910. #endif
  911. {
  912. struct bwb_line *current;
  913. register int s_level;
  914. int position;
  915. s_level = 1;
  916. for ( current = l->next; current != &CURTASK bwb_end; current = current->next )
  917. {
  918. position = 0;
  919. if ( current->marked != TRUE )
  920. {
  921. line_start( current->buffer, &position, &( current->lnpos ),
  922. &( current->lnum ),
  923. &( current->cmdpos ),
  924. &( current->cmdnum ),
  925. &( current->startpos ) );
  926. }
  927. current->position = current->startpos;
  928. if ( current->cmdnum > -1 )
  929. {
  930. if ( bwb_cmdtable[ current->cmdnum ].vector == bwb_sub )
  931. {
  932. ++s_level;
  933. #if INTENSIVE_DEBUG
  934. sprintf( bwb_ebuf, "in find_endsub(): found SUB at line %d, level %d",
  935. current->number, s_level );
  936. bwb_debug( bwb_ebuf );
  937. #endif
  938. }
  939. else if ( is_endsub( current ) == TRUE )
  940. {
  941. --s_level;
  942. #if INTENSIVE_DEBUG
  943. sprintf( bwb_ebuf, "in find_endsub(): found END SUB at line %d, level %d",
  944. current->number, s_level );
  945. bwb_debug( bwb_ebuf );
  946. #endif
  947. if ( s_level == 0 )
  948. {
  949. return current;
  950. }
  951. }
  952. }
  953. }
  954. #if PROG_ERRORS
  955. sprintf( bwb_ebuf, "SUB without END SUB" );
  956. bwb_error( bwb_ebuf );
  957. #else
  958. bwb_error( err_syntax );
  959. #endif
  960. return NULL;
  961. }
  962. /***************************************************************
  963. FUNCTION: is_endsub()
  964. DESCRIPTION: This function determines whether the
  965. line buffer for line 'l' is positioned
  966. at an END SUB statement.
  967. ***************************************************************/
  968. #if ANSI_C
  969. static int
  970. is_endsub( struct bwb_line *l )
  971. #else
  972. static int
  973. is_endsub( l )
  974. struct bwb_line *l;
  975. #endif
  976. {
  977. int position;
  978. char tbuf[ MAXVARNAMESIZE + 1];
  979. if ( bwb_cmdtable[ l->cmdnum ].vector != bwb_xend )
  980. {
  981. return FALSE;
  982. }
  983. position = l->startpos;
  984. adv_ws( l->buffer, &position );
  985. adv_element( l->buffer, &position, tbuf );
  986. bwb_strtoupper( tbuf );
  987. if ( strcmp( tbuf, "SUB" ) == 0 )
  988. {
  989. return TRUE;
  990. }
  991. return FALSE;
  992. }
  993. /***************************************************************
  994. FUNCTION: bwb_endsub()
  995. DESCRIPTION: This C function implements the BASIC
  996. END SUB command, ending a subroutine
  997. definition. Because the command END
  998. can have multiple meanings, this function
  999. should be called from the bwb_xend()
  1000. function, which should be able to identify
  1001. an END SUB command.
  1002. SYNTAX: END SUB
  1003. ***************************************************************/
  1004. #if ANSI_C
  1005. struct bwb_line *
  1006. bwb_endsub( struct bwb_line *line )
  1007. #else
  1008. struct bwb_line *
  1009. bwb_endsub( line )
  1010. struct bwb_line *line;
  1011. #endif
  1012. {
  1013. struct bwb_variable *l;
  1014. register int c;
  1015. /* assign local variable values to calling variables */
  1016. l = CURTASK excs[ CURTASK exsc ].local_variable;
  1017. for ( c = 0; c < CURTASK excs[ CURTASK exsc ].n_cvs; ++c )
  1018. {
  1019. bwb_vtov( CURTASK excs[ CURTASK exsc ].calling_variable[ c ], l );
  1020. l = l->next;
  1021. }
  1022. /* decrement the EXEC stack counter */
  1023. bwb_decexec();
  1024. /* if the previous level was EXEC_MAIN,
  1025. then execution continues from this point */
  1026. if ( CURTASK excs[ CURTASK exsc + 1 ].code == EXEC_MAIN )
  1027. {
  1028. return bwb_zline( line );
  1029. }
  1030. /* else return next from old line */
  1031. CURTASK excs[ CURTASK exsc ].line->next->position = 0;
  1032. return CURTASK excs[ CURTASK exsc ].line->next;
  1033. }
  1034. /***************************************************************
  1035. FUNCTION: find_label()
  1036. DESCRIPTION: This C function finds a program line that
  1037. begins with the label included in <buffer>.
  1038. ***************************************************************/
  1039. #if ANSI_C
  1040. extern struct bwb_line *
  1041. find_label( char *buffer )
  1042. #else
  1043. extern struct bwb_line *
  1044. find_label( buffer )
  1045. char *buffer;
  1046. #endif
  1047. {
  1048. struct fslte *f;
  1049. for ( f = CURTASK fslt_start.next; f != & ( CURTASK fslt_end ); f = f->next )
  1050. {
  1051. if ( strcmp( buffer, f->name ) == 0 )
  1052. {
  1053. #if INTENSIVE_DEBUG
  1054. sprintf( bwb_ebuf, "in find_label(): found label <%s>", buffer );
  1055. bwb_debug( bwb_ebuf );
  1056. #endif
  1057. return f->line;
  1058. }
  1059. }
  1060. #if PROG_ERRORS
  1061. sprintf( bwb_ebuf, "in find_label(): failed to find label <%s>", buffer );
  1062. bwb_error( bwb_ebuf );
  1063. #else
  1064. bwb_error( err_lnnotfound );
  1065. #endif
  1066. return NULL;
  1067. }
  1068. /***************************************************************
  1069. FUNCTION: bwb_doloop()
  1070. DESCRIPTION: This C function implements the ANSI BASIC
  1071. DO statement, when DO is not followed by
  1072. an argument. It is called by bwb_do() in
  1073. bwb_cmd.c.
  1074. SYNTAX: DO
  1075. ***************************************************************/
  1076. #if ANSI_C
  1077. struct bwb_line *
  1078. bwb_doloop( struct bwb_line *l )
  1079. #else
  1080. struct bwb_line *
  1081. bwb_doloop( l )
  1082. struct bwb_line *l;
  1083. #endif
  1084. {
  1085. /* if this is the first time at this DO statement, note it */
  1086. if ( CURTASK excs[ CURTASK exsc ].while_line != l )
  1087. {
  1088. bwb_incexec();
  1089. CURTASK excs[ CURTASK exsc ].while_line = l;
  1090. /* find the LOOP statement */
  1091. CURTASK excs[ CURTASK exsc ].wend_line = find_loop( l );
  1092. if ( CURTASK excs[ CURTASK exsc ].wend_line == NULL )
  1093. {
  1094. return bwb_zline( l );
  1095. }
  1096. #if INTENSIVE_DEBUG
  1097. sprintf( bwb_ebuf, "in bwb_doloop(): initialize DO loop, line <%d>",
  1098. l->number );
  1099. bwb_debug( bwb_ebuf );
  1100. #endif
  1101. }
  1102. #if INTENSIVE_DEBUG
  1103. else
  1104. {
  1105. sprintf( bwb_ebuf, "in bwb_doloop(): return to DO loop, line <%d>",
  1106. l->number );
  1107. bwb_debug( bwb_ebuf );
  1108. }
  1109. #endif
  1110. bwb_setexec( l, l->position, EXEC_DO );
  1111. return bwb_zline( l );
  1112. }
  1113. /***************************************************************
  1114. FUNCTION: bwb_loop()
  1115. DESCRIPTION: This C function implements the ANSI BASIC
  1116. LOOP statement.
  1117. SYNTAX: LOOP [UNTIL expression]
  1118. ***************************************************************/
  1119. #if ANSI_C
  1120. struct bwb_line *
  1121. bwb_loop( struct bwb_line *l )
  1122. #else
  1123. struct bwb_line *
  1124. bwb_loop( l )
  1125. struct bwb_line *l;
  1126. #endif
  1127. {
  1128. char tbuf[ MAXSTRINGSIZE + 1 ];
  1129. #if INTENSIVE_DEBUG
  1130. sprintf( bwb_ebuf, "in bwb_loop(): entered subroutine" );
  1131. bwb_debug( bwb_ebuf );
  1132. #endif
  1133. /* If the current exec stack is set for EXEC_WHILE, then we
  1134. presume that this is a LOOP statement ending a DO WHILE
  1135. loop */
  1136. if ( CURTASK excs[ CURTASK exsc ].code == EXEC_WHILE )
  1137. {
  1138. return bwb_wend( l );
  1139. }
  1140. /* check integrity of DO loop */
  1141. if ( CURTASK excs[ CURTASK exsc ].code != EXEC_DO )
  1142. {
  1143. #if PROG_ERRORS
  1144. sprintf( bwb_ebuf, "in bwb_loop(): exec stack code != EXEC_DO" );
  1145. bwb_error( bwb_ebuf );
  1146. #else
  1147. bwb_error( err_syntax );
  1148. #endif
  1149. }
  1150. if ( CURTASK excs[ CURTASK exsc ].while_line == NULL )
  1151. {
  1152. #if PROG_ERRORS
  1153. sprintf( bwb_ebuf, "in bwb_loop(): exec stack while_line == NULL" );
  1154. bwb_error( bwb_ebuf );
  1155. #else
  1156. bwb_error( err_syntax );
  1157. #endif
  1158. }
  1159. /* advance to find the first argument */
  1160. adv_element( l->buffer, &( l->position ), tbuf );
  1161. bwb_strtoupper( tbuf );
  1162. /* detect a LOOP UNTIL structure */
  1163. if ( strcmp( tbuf, CMD_XUNTIL ) == 0 )
  1164. {
  1165. #if INTENSIVE_DEBUG
  1166. sprintf( bwb_ebuf, "in bwb_loop(): detected LOOP UNTIL" );
  1167. bwb_debug( bwb_ebuf );
  1168. #endif
  1169. return bwb_loopuntil( l );
  1170. }
  1171. /* LOOP does not have UNTIL */
  1172. else
  1173. {
  1174. /* reset to the top of the current DO loop */
  1175. #if INTENSIVE_DEBUG
  1176. sprintf( bwb_ebuf, "in bwb_loop() return to line <%d>",
  1177. CURTASK excs[ CURTASK exsc ].while_line->number );
  1178. bwb_debug( bwb_ebuf );
  1179. #endif
  1180. CURTASK excs[ CURTASK exsc ].while_line->position = 0;
  1181. bwb_setexec( CURTASK excs[ CURTASK exsc ].while_line, 0, EXEC_DO );
  1182. return CURTASK excs[ CURTASK exsc ].while_line;
  1183. }
  1184. }
  1185. /***************************************************************
  1186. FUNCTION: bwb_loopuntil()
  1187. DESCRIPTION: This C function implements the ANSI BASIC
  1188. LOOP UNTIL statement and is called by
  1189. bwb_loop().
  1190. ***************************************************************/
  1191. #if ANSI_C
  1192. static struct bwb_line *
  1193. bwb_loopuntil( struct bwb_line *l )
  1194. #else
  1195. static struct bwb_line *
  1196. bwb_loopuntil( l )
  1197. struct bwb_line *l;
  1198. #endif
  1199. {
  1200. struct exp_ese *e;
  1201. struct bwb_line *r;
  1202. #if INTENSIVE_DEBUG
  1203. sprintf( bwb_ebuf, "in bwb_loopuntil(): entered subroutine" );
  1204. bwb_debug( bwb_ebuf );
  1205. #endif
  1206. /* call bwb_exp() to interpret the expression */
  1207. e = bwb_exp( l->buffer, FALSE, &( l->position ) );
  1208. if ( (int) exp_getnval( e ) == TRUE )
  1209. {
  1210. CURTASK excs[ CURTASK exsc ].while_line = NULL;
  1211. r = CURTASK excs[ CURTASK exsc ].wend_line;
  1212. bwb_setexec( r, 0, CURTASK excs[ CURTASK exsc - 1 ].code );
  1213. r->position = 0;
  1214. bwb_decexec();
  1215. return r;
  1216. }
  1217. /* condition is false: loop around to DO again */
  1218. else
  1219. {
  1220. #if INTENSIVE_DEBUG
  1221. sprintf( bwb_ebuf, "in bwb_loopuntil() return to line <%d>",
  1222. CURTASK excs[ CURTASK exsc ].while_line->number );
  1223. bwb_debug( bwb_ebuf );
  1224. #endif
  1225. CURTASK excs[ CURTASK exsc ].while_line->position = 0;
  1226. bwb_setexec( CURTASK excs[ CURTASK exsc ].while_line, 0, EXEC_DO );
  1227. return CURTASK excs[ CURTASK exsc ].while_line;
  1228. }
  1229. }
  1230. /***************************************************************
  1231. FUNCTION: bwb_exit()
  1232. DESCRIPTION: This C function implements the BASIC EXIT
  1233. statement, calling subroutines for either
  1234. EXIT FOR or EXIT DO.
  1235. SYNTAX: EXIT FOR|DO
  1236. ***************************************************************/
  1237. #if ANSI_C
  1238. struct bwb_line *
  1239. bwb_exit( struct bwb_line *l )
  1240. #else
  1241. struct bwb_line *
  1242. bwb_exit( l )
  1243. struct bwb_line *l;
  1244. #endif
  1245. {
  1246. char tbuf[ MAXSTRINGSIZE + 1 ];
  1247. #if INTENSIVE_DEBUG
  1248. sprintf( bwb_ebuf, "in bwb_exit(): entered subroutine" );
  1249. bwb_debug( bwb_ebuf );
  1250. #endif
  1251. adv_element( l->buffer, &( l->position ), tbuf );
  1252. bwb_strtoupper( tbuf );
  1253. if ( strcmp( tbuf, CMD_XFOR ) == 0 )
  1254. {
  1255. #if INTENSIVE_DEBUG
  1256. sprintf( bwb_ebuf, "in bwb_exit(): detected EXIT FOR" );
  1257. bwb_debug( bwb_ebuf );
  1258. #endif
  1259. return bwb_exitfor( l );
  1260. }
  1261. if ( strcmp( tbuf, CMD_XDO ) == 0 )
  1262. {
  1263. return bwb_exitdo( l );
  1264. }
  1265. #if PROG_ERRORS
  1266. sprintf( bwb_ebuf, "in bwb_exit(): Nonsense or nothing following EXIT" );
  1267. bwb_error( bwb_ebuf );
  1268. #else
  1269. bwb_error( err_syntax );
  1270. #endif
  1271. return bwb_zline( l );
  1272. }
  1273. /***************************************************************
  1274. FUNCTION: bwb_exitdo()
  1275. DESCRIPTION: This function handles the BASIC EXIT
  1276. DO statement. This is a structured
  1277. programming command compatible with ANSI
  1278. BASIC. It is called from the bwb_exit()
  1279. subroutine.
  1280. ***************************************************************/
  1281. #if ANSI_C
  1282. struct bwb_line *
  1283. bwb_exitdo( struct bwb_line *l )
  1284. #else
  1285. struct bwb_line *
  1286. bwb_exitdo( l )
  1287. struct bwb_line *l;
  1288. #endif
  1289. {
  1290. struct bwb_line *next_line;
  1291. int found;
  1292. register int level;
  1293. #if INTENSIVE_DEBUG
  1294. sprintf( bwb_ebuf, "in bwb_exitdo(): entered subroutine" );
  1295. bwb_debug( bwb_ebuf );
  1296. #endif
  1297. /* Check the integrity of the DO statement */
  1298. found = FALSE;
  1299. level = CURTASK exsc;
  1300. do
  1301. {
  1302. if ( CURTASK excs[ level ].code == EXEC_DO )
  1303. {
  1304. next_line = CURTASK excs[ CURTASK level ].wend_line;
  1305. found = TRUE;
  1306. }
  1307. else
  1308. {
  1309. --level;
  1310. }
  1311. }
  1312. while ( ( level >= 0 ) && ( found == FALSE ) );
  1313. if ( found != TRUE )
  1314. {
  1315. #if PROG_ERRORS
  1316. sprintf( bwb_ebuf, "in bwb_exitfor(): EXIT DO without DO" );
  1317. bwb_error( bwb_ebuf );
  1318. #else
  1319. bwb_error( err_syntax );
  1320. #endif
  1321. return bwb_zline( l );
  1322. }
  1323. #if INTENSIVE_DEBUG
  1324. sprintf( bwb_ebuf, "in bwb_exitdo(): level found is <%d>, current <%d>",
  1325. level, CURTASK exsc );
  1326. bwb_debug( bwb_ebuf );
  1327. #endif
  1328. /* decrement below the level of the NEXT statement */
  1329. while( CURTASK exsc >= level )
  1330. {
  1331. bwb_decexec();
  1332. }
  1333. /* set the next line in the exec stack */
  1334. next_line->position = 0;
  1335. bwb_setexec( next_line, 0, EXEC_NORM );
  1336. return next_line;
  1337. }
  1338. #endif /* STRUCT_CMDS */
  1339. /***************************************************************
  1340. FUNCTION: bwb_vtov()
  1341. DESCRIPTION: This function assigns the value of one
  1342. bwBASIC variable (src) to the value of another
  1343. bwBASIC variable (dst).
  1344. ***************************************************************/
  1345. #if ANSI_C
  1346. struct bwb_variable *
  1347. bwb_vtov( struct bwb_variable *dst,
  1348. struct bwb_variable *src )
  1349. #else
  1350. struct bwb_variable *
  1351. bwb_vtov( dst, src )
  1352. struct bwb_variable *dst;
  1353. struct bwb_variable *src;
  1354. #endif
  1355. {
  1356. if ( dst == src )
  1357. {
  1358. return dst;
  1359. }
  1360. if ( src->type != dst->type )
  1361. {
  1362. #if PROG_ERRORS
  1363. sprintf( bwb_ebuf, "in bwb_vtov(): mismatch src <%s> type <%d> dst <%s> type <%d>",
  1364. src->name, src->type, dst->name, dst->type );
  1365. bwb_error( bwb_ebuf );
  1366. #else
  1367. bwb_error( err_mismatch );
  1368. #endif
  1369. return NULL;
  1370. }
  1371. if ( dst->type == NUMBER )
  1372. {
  1373. #if INTENSIVE_DEBUG
  1374. sprintf( bwb_ebuf, "in bwb_vtov(): assigning var <%s> val <%lf> to var <%s>",
  1375. src->name, var_getnval( src ), dst->name );
  1376. bwb_debug( bwb_ebuf );
  1377. #endif
  1378. * var_findnval( dst, dst->array_pos ) = var_getnval( src );
  1379. }
  1380. else
  1381. {
  1382. str_btob( var_getsval( dst ), var_getsval( src ) );
  1383. }
  1384. return dst;
  1385. }
  1386. /***************************************************************
  1387. FUNCTION: bwb_etov()
  1388. DESCRIPTION: This function assigns the value of a
  1389. bwBASIC expression stack element (src)
  1390. to the value of a bwBASIC variable (dst).
  1391. ***************************************************************/
  1392. #if ANSI_C
  1393. struct bwb_variable *
  1394. bwb_etov( struct bwb_variable *dst, struct exp_ese *src )
  1395. #else
  1396. struct bwb_variable *
  1397. bwb_etov( dst, src )
  1398. struct bwb_variable *dst;
  1399. struct exp_ese *src;
  1400. #endif
  1401. {
  1402. if ( (int) src->type != dst->type )
  1403. {
  1404. #if PROG_ERRORS
  1405. sprintf( bwb_ebuf, "in bwb_etov(): mismatch src <%d> dst <%d>",
  1406. src->type, dst->type );
  1407. bwb_error( bwb_ebuf );
  1408. #else
  1409. bwb_error( err_mismatch );
  1410. #endif
  1411. return NULL;
  1412. }
  1413. if ( dst->type == NUMBER )
  1414. {
  1415. * var_findnval( dst, dst->array_pos ) = exp_getnval( src );
  1416. }
  1417. else
  1418. {
  1419. str_btob( var_getsval( dst ), exp_getsval( src ) );
  1420. }
  1421. return dst;
  1422. }
  1423. /***************************************************************
  1424. FUNCTION: var_pos()
  1425. DESCRIPTION: This function returns the name of a
  1426. local variable at a specified position
  1427. in the local variable list.
  1428. ***************************************************************/
  1429. #if ANSI_C
  1430. struct bwb_variable *
  1431. var_pos( struct bwb_variable *firstvar, int p )
  1432. #else
  1433. struct bwb_variable *
  1434. var_pos( firstvar, p )
  1435. struct bwb_variable *firstvar;
  1436. int p;
  1437. #endif
  1438. {
  1439. register int c;
  1440. struct bwb_variable *v;
  1441. v = firstvar;
  1442. for ( c = 0; c != p; ++c )
  1443. {
  1444. v = v->next;
  1445. }
  1446. #if INTENSIVE_DEBUG
  1447. sprintf( bwb_ebuf, "in var_pos(): returning pos <%d> variable <%s>",
  1448. p, v->name );
  1449. bwb_debug( bwb_ebuf );
  1450. #endif
  1451. return v;
  1452. }
  1453. /***************************************************************
  1454. FUNCTION: fslt_addcallvar()
  1455. DESCRIPTION: This function adds a calling variable
  1456. to the FUNCTION-SUB lookuop table at
  1457. a specific level.
  1458. ***************************************************************/
  1459. #if ANSI_C
  1460. int
  1461. fslt_addcallvar( struct bwb_variable *v )
  1462. #else
  1463. int
  1464. fslt_addcallvar( v )
  1465. struct bwb_variable *v;
  1466. #endif
  1467. {
  1468. if ( CURTASK excs[ CURTASK exsc ].n_cvs >= MAX_FARGS )
  1469. {
  1470. #if PROG_ERRORS
  1471. sprintf( bwb_ebuf, "in fslt_addcallvar(): Maximum number of Function Args Exceeded" );
  1472. bwb_error( bwb_ebuf );
  1473. #else
  1474. bwb_error( err_overflow );
  1475. #endif
  1476. }
  1477. CURTASK excs[ CURTASK exsc ].calling_variable[ CURTASK excs[ CURTASK exsc ].n_cvs ] = v;
  1478. ++CURTASK excs[ CURTASK exsc ].n_cvs;
  1479. return TRUE;
  1480. }
  1481. /***************************************************************
  1482. FUNCTION: expufnc()
  1483. DESCRIPTION: This C function interprets a user-defined
  1484. function, returning its value at the current
  1485. level of the expression stack.
  1486. ***************************************************************/
  1487. #if ANSI_C
  1488. int
  1489. exp_ufnc( char *expression )
  1490. #else
  1491. int
  1492. exp_ufnc( expression )
  1493. char *expression;
  1494. #endif
  1495. {
  1496. char tbuf[ MAXSTRINGSIZE + 1 ];
  1497. struct bwb_line *call_line;
  1498. struct fslte *f, *c;
  1499. struct bwb_variable *v, *r;
  1500. struct exp_ese *e;
  1501. int save_elevel;
  1502. int position, epos;
  1503. #if INTENSIVE_DEBUG
  1504. register int i;
  1505. #endif
  1506. position = 0;
  1507. /* get the function name in tbuf */
  1508. exp_getvfname( expression, tbuf );
  1509. /* find the function name in the function-subroutine lookup table */
  1510. for ( f = CURTASK fslt_start.next; f != &CURTASK fslt_end; f = f->next )
  1511. {
  1512. if ( strcmp( f->name, tbuf ) == 0 )
  1513. {
  1514. #if INTENSIVE_DEBUG
  1515. sprintf( bwb_ebuf, "in exp_ufnc(): found user function <%s>",
  1516. tbuf );
  1517. bwb_debug( bwb_ebuf );
  1518. #endif
  1519. c = f; /* current function-subroutine lookup table element */
  1520. call_line = f->line; /* line to call for function */
  1521. }
  1522. }
  1523. #if INTENSIVE_DEBUG
  1524. sprintf( bwb_ebuf, "in exp_ufnc(): call to function <%s>", tbuf );
  1525. bwb_debug( bwb_ebuf );
  1526. #endif
  1527. position += strlen( tbuf );
  1528. #if INTENSIVE_DEBUG
  1529. sprintf( bwb_ebuf, "in exp_ufnc(): found line <%s>",
  1530. call_line->buffer );
  1531. bwb_debug( bwb_ebuf );
  1532. #endif
  1533. /* save the old position on the EXEC stack */
  1534. bwb_setexec( CURTASK excs[ CURTASK exsc ].line,
  1535. position, CURTASK excs[ CURTASK exsc ].code );
  1536. save_elevel = CURTASK exsc;
  1537. /* increment and set new EXEC stack */
  1538. bwb_incexec();
  1539. call_line->position = 0;
  1540. bwb_setexec( call_line, 0, EXEC_FUNCTION );
  1541. /* attach local variables */
  1542. CURTASK excs[ CURTASK exsc ].local_variable = c->local_variable;
  1543. #if INTENSIVE_DEBUG
  1544. i = 0;
  1545. sprintf( bwb_ebuf, "in exp_ufnc(): <%s> attached local variables EXEC level <%d>",
  1546. tbuf, CURTASK exsc );
  1547. bwb_debug( bwb_ebuf );
  1548. for ( v = CURTASK excs[ CURTASK exsc ].local_variable; v != NULL; v = v->next )
  1549. {
  1550. sprintf( bwb_ebuf, "in exp_ufnc(): <%s> level <%d> variable <%d> name <%s>",
  1551. tbuf, CURTASK exsc, i, v->name );
  1552. bwb_debug( bwb_ebuf );
  1553. ++i;
  1554. }
  1555. getchar();
  1556. #endif
  1557. /* read calling variables for this call */
  1558. call_readargs( c, expression, &position );
  1559. #if INTENSIVE_DEBUG
  1560. sprintf( bwb_ebuf, "in exp_ufnc(): current buffer <%s>",
  1561. &( call_line->buffer[ c->startpos ] ) );
  1562. bwb_debug( bwb_ebuf );
  1563. #endif
  1564. /* determine if single-line function */
  1565. epos = c->startpos;
  1566. adv_ws( call_line->buffer, &epos );
  1567. if ( call_line->buffer[ epos ] == '=' )
  1568. {
  1569. #if INTENSIVE_DEBUG
  1570. sprintf( bwb_ebuf, "in exp_ufnc(): found SINGLE-LINE function" );
  1571. bwb_debug( bwb_ebuf );
  1572. #endif
  1573. ++epos;
  1574. call_line->position = epos;
  1575. bwb_setexec( call_line, epos, EXEC_FUNCTION );
  1576. #if INTENSIVE_DEBUG
  1577. sprintf( bwb_ebuf, "in exp_ufnc(): single line: parse <%s>",
  1578. &( call_line->buffer[ epos ] ) );
  1579. bwb_debug( bwb_ebuf );
  1580. #endif
  1581. e = bwb_exp( call_line->buffer, FALSE, &epos );
  1582. v = var_find( tbuf );
  1583. #if INTENSIVE_DEBUG
  1584. if ( e->type == STRING )
  1585. {
  1586. sprintf( bwb_ebuf, "in exp_ufnc(): expression returns <%d>-byte string",
  1587. exp_getsval( e )->length );
  1588. bwb_debug( bwb_ebuf );
  1589. }
  1590. else
  1591. {
  1592. sprintf( bwb_ebuf, "in exp_ufnc(): expression returns number <%lf>",
  1593. (double) exp_getnval( e ) );
  1594. bwb_debug( bwb_ebuf );
  1595. }
  1596. #endif
  1597. #if INTENSIVE_DEBUG
  1598. sprintf( bwb_ebuf, "in exp_ufnc(): single line after parsing, <%s>",
  1599. &( call_line->buffer[ epos ] ) );
  1600. bwb_debug( bwb_ebuf );
  1601. #endif
  1602. bwb_etov( v, e );
  1603. bwb_decexec();
  1604. }
  1605. /* multi-line function must be executed now */
  1606. else
  1607. {
  1608. #if INTENSIVE_DEBUG
  1609. sprintf( bwb_ebuf, "in exp_ufnc(): found MULTI-LINE function" );
  1610. bwb_debug( bwb_ebuf );
  1611. #endif
  1612. /* now execute until function is resolved */
  1613. bwb_execline();
  1614. while( CURTASK exsc > save_elevel )
  1615. {
  1616. bwb_execline();
  1617. }
  1618. /* find the return value */
  1619. for ( r = c->local_variable; r != NULL; r = r->next )
  1620. {
  1621. if ( strcmp( r->name, c->name ) == 0 )
  1622. {
  1623. v = r;
  1624. }
  1625. }
  1626. }
  1627. /* now place value in expression stack */
  1628. CURTASK exps[ CURTASK expsc ].type = (char) v->type;
  1629. CURTASK exps[ CURTASK expsc ].pos_adv = position;
  1630. switch( v->type )
  1631. {
  1632. case STRING:
  1633. CURTASK exps[ CURTASK expsc ].operation = CONST_STRING;
  1634. #if INTENSIVE_DEBUG
  1635. sprintf( bwb_ebuf, "in exp_ufnc(): ready to assign <%d>-byte STRING",
  1636. var_getsval( v )->length );
  1637. bwb_debug( bwb_ebuf );
  1638. #endif
  1639. str_btob( exp_getsval( &( CURTASK exps[ CURTASK expsc ] )),
  1640. var_getsval( v ) );
  1641. #if INTENSIVE_DEBUG
  1642. str_btoc( tbuf, var_getsval( v ) );
  1643. sprintf( bwb_ebuf, "in exp_ufnc(): string assigned <%s>", tbuf );
  1644. bwb_debug( bwb_ebuf );
  1645. #endif
  1646. break;
  1647. default:
  1648. CURTASK exps[ CURTASK expsc ].operation = NUMBER;
  1649. CURTASK exps[ CURTASK expsc ].nval = var_getnval( v );
  1650. break;
  1651. }
  1652. return TRUE;
  1653. }
  1654. /***************************************************************
  1655. FUNCTION: fslt_addlocalvar()
  1656. DESCRIPTION: This function adds a local variable
  1657. to the FUNCTION-SUB lookuop table at
  1658. a specific level.
  1659. ***************************************************************/
  1660. #if ANSI_C
  1661. int
  1662. fslt_addlocalvar( struct fslte *f, struct bwb_variable *v )
  1663. #else
  1664. int
  1665. fslt_addlocalvar( f, v )
  1666. struct fslte *f;
  1667. struct bwb_variable *v;
  1668. #endif
  1669. {
  1670. struct bwb_variable *c, *p;
  1671. #if INTENSIVE_DEBUG
  1672. register int i;
  1673. #endif
  1674. /* find end of local chain */
  1675. if ( f->local_variable == NULL )
  1676. {
  1677. #if INTENSIVE_DEBUG
  1678. i = 0;
  1679. #endif
  1680. f->local_variable = v;
  1681. }
  1682. else
  1683. {
  1684. #if INTENSIVE_DEBUG
  1685. i = 1;
  1686. #endif
  1687. p = f->local_variable;
  1688. for ( c = f->local_variable->next; c != NULL; c = c->next )
  1689. {
  1690. p = c;
  1691. #if INTENSIVE_DEBUG
  1692. ++i;
  1693. #endif
  1694. }
  1695. p->next = v;
  1696. }
  1697. v->next = NULL;
  1698. #if INTENSIVE_DEBUG
  1699. sprintf( bwb_ebuf, "in fslt_addlocalvar(): added local variable variable <%s> arg number <%d>",
  1700. v->name, i );
  1701. bwb_debug( bwb_ebuf );
  1702. getchar();
  1703. #endif
  1704. return TRUE;
  1705. }
  1706. /***************************************************************
  1707. FUNCTION: fslt_init()
  1708. DESCRIPTION: This function initializes the FUNCTION-SUB
  1709. lookup table.
  1710. ***************************************************************/
  1711. #if ANSI_C
  1712. int
  1713. fslt_init( int task )
  1714. #else
  1715. int
  1716. fslt_init( task )
  1717. int task;
  1718. #endif
  1719. {
  1720. LOCALTASK fslt_start.next = &(LOCALTASK fslt_end);
  1721. return TRUE;
  1722. }
  1723. /***************************************************************
  1724. FUNCTION: is_label()
  1725. DESCRIPTION: This function determines whether the string
  1726. pointed to by 'buffer' is a label (i.e.,
  1727. ends with colon).
  1728. ***************************************************************/
  1729. #if ANSI_C
  1730. extern int
  1731. is_label( char *buffer )
  1732. #else
  1733. int
  1734. is_label( buffer )
  1735. char *buffer;
  1736. #endif
  1737. {
  1738. #if INTENSIVE_DEBUG
  1739. sprintf( bwb_ebuf, "in is_label(): check element <%s>", buffer );
  1740. bwb_debug( bwb_ebuf );
  1741. #endif
  1742. if ( buffer[ strlen( buffer ) - 1 ] == ':' )
  1743. {
  1744. return TRUE;
  1745. }
  1746. else
  1747. {
  1748. return FALSE;
  1749. }
  1750. }
  1751.