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.
 
 
 
 
 
 

955 lines
20 KiB

  1. /***************************************************************f
  2. bwb_int.c Line Interpretation Routines
  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 <ctype.h>
  19. #include "bwbasic.h"
  20. #include "bwb_mes.h"
  21. /***************************************************************
  22. FUNCTION: adv_element()
  23. DESCRIPTION: This function reads characters in <buffer>
  24. beginning at <pos> and advances past a
  25. line element, incrementing <pos> appropri-
  26. ately and returning the line element in
  27. <element>.
  28. ***************************************************************/
  29. #if ANSI_C
  30. int
  31. adv_element( char *buffer, int *pos, char *element )
  32. #else
  33. int
  34. adv_element( buffer, pos, element )
  35. char *buffer;
  36. int *pos;
  37. char *element;
  38. #endif
  39. {
  40. int loop; /* control loop */
  41. int e_pos; /* position in element buffer */
  42. int str_const; /* boolean: building a string constant */
  43. /* advance beyond any initial whitespace */
  44. adv_ws( buffer, pos );
  45. #if INTENSIVE_DEBUG
  46. sprintf( bwb_ebuf, "in adv_element(): receieved <%s>.", &( buffer[ *pos ] ));
  47. bwb_debug( bwb_ebuf );
  48. #endif
  49. /* now loop while building an element and looking for an
  50. element terminator */
  51. loop = TRUE;
  52. e_pos = 0;
  53. element[ e_pos ] = '\0';
  54. str_const = FALSE;
  55. while ( loop == TRUE )
  56. {
  57. switch( buffer[ *pos ] )
  58. {
  59. case ',': /* element terminators */
  60. case ';':
  61. #if MULTISEG_LINES
  62. case ':':
  63. #endif
  64. case '=':
  65. case ' ':
  66. case '\t':
  67. case '\0':
  68. case '\n':
  69. case '\r':
  70. if ( str_const == TRUE )
  71. {
  72. element[ e_pos ] = buffer[ *pos ];
  73. ++e_pos;
  74. ++( *pos );
  75. element[ e_pos ] = '\0';
  76. }
  77. else
  78. {
  79. return TRUE;
  80. }
  81. break;
  82. case '\"': /* string constant */
  83. element[ e_pos ] = buffer[ *pos ];
  84. ++e_pos;
  85. ++( *pos );
  86. element[ e_pos ] = '\0';
  87. if ( str_const == TRUE ) /* termination of string constant */
  88. {
  89. return TRUE;
  90. }
  91. else /* beginning of string constant */
  92. {
  93. str_const = TRUE;
  94. }
  95. break;
  96. default:
  97. element[ e_pos ] = buffer[ *pos ];
  98. ++e_pos;
  99. ++( *pos );
  100. element[ e_pos ] = '\0';
  101. break;
  102. }
  103. }
  104. /* This should not happen */
  105. return FALSE;
  106. }
  107. /***************************************************************
  108. FUNCTION: adv_ws()
  109. DESCRIPTION: This function reads characters in <buffer>
  110. beginning at <pos> and advances past any
  111. whitespace, incrementing <pos> appropri-
  112. ately.
  113. ***************************************************************/
  114. #if ANSI_C
  115. int
  116. adv_ws( char *buffer, int *pos )
  117. #else
  118. int
  119. adv_ws( buffer, pos )
  120. char *buffer;
  121. int *pos;
  122. #endif
  123. {
  124. int loop;
  125. loop = TRUE;
  126. while ( loop == TRUE )
  127. {
  128. switch( buffer[ *pos ] )
  129. {
  130. case ' ':
  131. case '\t':
  132. ++( *pos );
  133. break;
  134. default:
  135. return TRUE;
  136. }
  137. }
  138. /* This should not happen */
  139. return FALSE;
  140. }
  141. /***************************************************************
  142. FUNCTION: adv_eos()
  143. DESCRIPTION: This function reads characters in <buffer>
  144. beginning at <pos> and advances to the
  145. end of a segment delimited by ':',
  146. incrementing <pos> appropriately.
  147. ***************************************************************/
  148. #if MULTISEG_LINES
  149. #if ANSI_C
  150. int
  151. adv_eos( char *buffer, int *pos )
  152. #else
  153. int
  154. adv_eos( buffer, pos )
  155. char *buffer;
  156. int *pos;
  157. #endif
  158. {
  159. int loop;
  160. loop = TRUE;
  161. while ( loop == TRUE )
  162. {
  163. if ( is_eol( buffer, pos ) == TRUE )
  164. {
  165. return FALSE;
  166. }
  167. switch( buffer[ *pos ] )
  168. {
  169. case ':': /* end of segment marker */
  170. ++( *pos );
  171. return TRUE;
  172. case '\"': /* begin quoted string */
  173. ++( *pos );
  174. while ( buffer[ *pos ] != '\"' )
  175. {
  176. if ( is_eol( buffer, pos ) == TRUE )
  177. {
  178. return FALSE;
  179. }
  180. else
  181. {
  182. ++( *pos );
  183. }
  184. }
  185. break;
  186. default:
  187. ++( *pos );
  188. }
  189. }
  190. /* This should not happen */
  191. return FALSE;
  192. }
  193. #endif /* MULTISEG_LINES */
  194. /***************************************************************
  195. FUNCTION: bwb_strtoupper()
  196. DESCRIPTION: This function converts the string in
  197. <buffer> to upper-case characters.
  198. ***************************************************************/
  199. #if ANSI_C
  200. int
  201. bwb_strtoupper( char *buffer )
  202. #else
  203. int
  204. bwb_strtoupper( buffer )
  205. char *buffer;
  206. #endif
  207. {
  208. char *p;
  209. p = buffer;
  210. while ( *p != '\0' )
  211. {
  212. if ( islower( *p ) != FALSE )
  213. {
  214. *p = (char) toupper( *p );
  215. }
  216. ++p;
  217. }
  218. return TRUE;
  219. }
  220. /***************************************************************
  221. FUNCTION: line_start()
  222. DESCRIPTION: This function reads a line buffer in
  223. <buffer> beginning at the position
  224. <pos> and attempts to determine (a)
  225. the position of the line number in the
  226. buffer (returned in <lnpos>), (b) the
  227. line number at this position (returned
  228. in <lnum>), (c) the position of the
  229. BASIC command in the buffer (returned
  230. in <cmdpos>), (d) the position of this
  231. BASIC command in the command table
  232. (returned in <cmdnum>), and (e) the
  233. position of the beginning of the rest
  234. of the line (returned in <startpos>).
  235. Although <startpos> must be returned
  236. as a positive integer, the other
  237. searches may fail, in which case FALSE
  238. will be returned in their positions.
  239. <pos> is not incremented.
  240. ***************************************************************/
  241. #if ANSI_C
  242. int
  243. line_start( char *buffer, int *pos, int *lnpos, int *lnum, int *cmdpos,
  244. int *cmdnum, int *startpos )
  245. #else
  246. int
  247. line_start( buffer, pos, lnpos, lnum, cmdpos, cmdnum, startpos )
  248. char *buffer;
  249. int *pos;
  250. int *lnpos;
  251. int *lnum;
  252. int *cmdpos;
  253. int *cmdnum;
  254. int *startpos;
  255. #endif
  256. {
  257. static int position;
  258. static char *tbuf;
  259. static int init = FALSE;
  260. /* get memory for temporary buffer if necessary */
  261. if ( init == FALSE )
  262. {
  263. init = TRUE;
  264. if ( ( tbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  265. {
  266. #if PROG_ERRORS
  267. bwb_error( "in line_start(): failed to get memory for tbuf" );
  268. #else
  269. bwb_error( err_getmem );
  270. #endif
  271. }
  272. }
  273. #if INTENSIVE_DEBUG
  274. sprintf( bwb_ebuf, "in line_start(): pos <%d> buffer <%s>", *pos,
  275. buffer );
  276. bwb_debug( bwb_ebuf );
  277. #endif
  278. /* set initial values */
  279. *startpos = position = *pos;
  280. *cmdpos = *lnpos = *pos;
  281. *cmdnum = *lnum = -1;
  282. /* check for null line */
  283. adv_ws( buffer, &position );
  284. if ( buffer[ position ] == '\0' )
  285. {
  286. #if INTENSIVE_DEBUG
  287. bwb_debug( "in line_start(): found NULL line" );
  288. #endif
  289. *cmdnum = getcmdnum( CMD_REM );
  290. return TRUE;
  291. }
  292. /* advance beyond the first element */
  293. *lnpos = position;
  294. scan_element( buffer, &position, tbuf );
  295. adv_ws( buffer, &position );
  296. /* test for a line number in the first element */
  297. if ( is_numconst( tbuf ) == TRUE ) /* a line number */
  298. {
  299. *lnum = atoi( tbuf );
  300. *startpos = position; /* temp */
  301. *cmdpos = position;
  302. scan_element( buffer, &position, tbuf ); /* advance past next element */
  303. #if INTENSIVE_DEBUG
  304. sprintf( bwb_ebuf, "in line_start(): new element is <%s>", tbuf );
  305. bwb_debug( bwb_ebuf );
  306. #endif
  307. #if STRUCT_CMDS
  308. if ( is_label( tbuf ) == TRUE )
  309. {
  310. *cmdnum = getcmdnum( CMD_LABEL );
  311. adv_ws( buffer, &position );
  312. *startpos = position;
  313. }
  314. else if ( is_cmd( tbuf, cmdnum ) == TRUE )
  315. #else
  316. if ( is_cmd( tbuf, cmdnum ) == TRUE )
  317. #endif
  318. {
  319. adv_ws( buffer, &position );
  320. *startpos = position;
  321. }
  322. else if ( is_let( &( buffer[ *cmdpos ] ), cmdnum ) == TRUE )
  323. {
  324. *cmdpos = -1;
  325. }
  326. else
  327. {
  328. *cmdpos = *cmdnum = -1;
  329. }
  330. }
  331. /* not a line number */
  332. else
  333. {
  334. *lnum = -1;
  335. *lnpos = -1;
  336. #if INTENSIVE_DEBUG
  337. sprintf( bwb_ebuf, "in line_start(): no line number, element <%s>.",
  338. tbuf );
  339. bwb_debug( bwb_ebuf );
  340. #endif
  341. #if STRUCT_CMDS
  342. if ( is_label( tbuf ) == TRUE )
  343. {
  344. #if INTENSIVE_DEBUG
  345. sprintf( bwb_ebuf, "in line_start(): label detected <%s>.",
  346. tbuf );
  347. bwb_debug( bwb_ebuf );
  348. #endif
  349. *cmdnum = getcmdnum( CMD_LABEL );
  350. adv_ws( buffer, &position );
  351. *startpos = position;
  352. }
  353. else if ( is_cmd( tbuf, cmdnum ) == TRUE )
  354. #else
  355. if ( is_cmd( tbuf, cmdnum ) == TRUE )
  356. #endif
  357. {
  358. adv_ws( buffer, &position );
  359. *startpos = position;
  360. }
  361. else if ( is_let( &( buffer[ position ] ), cmdnum ) == TRUE )
  362. {
  363. adv_ws( buffer, &position );
  364. *cmdpos = -1;
  365. }
  366. else
  367. {
  368. *cmdpos = *cmdnum = -1;
  369. }
  370. }
  371. #if INTENSIVE_DEBUG
  372. sprintf( bwb_ebuf, "in line_start(): lnpos <%d> lnum <%d>",
  373. *lnpos, *lnum );
  374. bwb_debug( bwb_ebuf );
  375. sprintf( bwb_ebuf, "in line_start(): cmdpos <%d> cmdnum <%d> startpos <%d>",
  376. *cmdpos, *cmdnum, *startpos );
  377. bwb_debug( bwb_ebuf );
  378. #endif
  379. /* return */
  380. return TRUE;
  381. }
  382. /***************************************************************
  383. FUNCTION: is_cmd()
  384. DESCRIPTION: This function determines whether the
  385. string in 'buffer' is a BASIC command
  386. statement, returning TRUE or FALSE,
  387. and if TRUE returning the command number
  388. in the command lookup table in the
  389. integer pointed to by 'cmdnum'.
  390. ***************************************************************/
  391. #if ANSI_C
  392. int
  393. is_cmd( char *buffer, int *cmdnum )
  394. #else
  395. int
  396. is_cmd( buffer, cmdnum )
  397. char *buffer;
  398. int *cmdnum;
  399. #endif
  400. {
  401. register int n;
  402. /* Convert the command name to upper case */
  403. bwb_strtoupper( buffer );
  404. /* Go through the command table and search for a match. */
  405. for ( n = 0; n < COMMANDS; ++n )
  406. {
  407. if ( strcmp( bwb_cmdtable[ n ].name, buffer ) == 0 )
  408. {
  409. *cmdnum = n;
  410. return TRUE;
  411. }
  412. }
  413. /* No command name was found */
  414. *cmdnum = -1;
  415. return FALSE;
  416. }
  417. /***************************************************************
  418. FUNCTION: is_let()
  419. DESCRIPTION: This function tries to determine if the
  420. expression in <buffer> is a LET statement
  421. without the LET command specified.
  422. ***************************************************************/
  423. #if ANSI_C
  424. int
  425. is_let( char *buffer, int *cmdnum )
  426. #else
  427. int
  428. is_let( buffer, cmdnum )
  429. char *buffer;
  430. int *cmdnum;
  431. #endif
  432. {
  433. register int n, i;
  434. #if INTENSIVE_DEBUG
  435. sprintf( bwb_ebuf, "in is_let(): buffer <%s>", buffer );
  436. bwb_debug( bwb_ebuf );
  437. #endif
  438. /* Go through the expression and search for an assignment operator. */
  439. for ( n = 0; buffer[ n ] != '\0'; ++n )
  440. {
  441. switch( buffer[ n ] )
  442. {
  443. case '\"': /* string constant */
  444. ++n;
  445. while( buffer[ n ] != '\"' )
  446. {
  447. ++n;
  448. if ( buffer[ n ] == '\0' )
  449. {
  450. #if PROG_ERRORS
  451. sprintf( bwb_ebuf, "Incomplete string constant" );
  452. bwb_error( bwb_ebuf );
  453. #else
  454. bwb_error( err_syntax );
  455. #endif
  456. *cmdnum = -1;
  457. return FALSE;
  458. }
  459. }
  460. ++n;
  461. break;
  462. case '=':
  463. #if INTENSIVE_DEBUG
  464. sprintf( bwb_ebuf, "in is_let(): implied LET found." );
  465. bwb_debug( bwb_ebuf );
  466. #endif
  467. for ( i = 0; i < COMMANDS; ++i )
  468. {
  469. if ( strncmp( bwb_cmdtable[ i ].name, "LET", (size_t) 3 ) == 0 )
  470. {
  471. *cmdnum = i;
  472. }
  473. }
  474. return TRUE;
  475. }
  476. }
  477. /* No command name was found */
  478. *cmdnum = -1;
  479. return FALSE;
  480. }
  481. /***************************************************************
  482. FUNCTION: bwb_stripcr()
  483. DESCRIPTION: This function strips the carriage return
  484. or line-feed from the end of a string.
  485. ***************************************************************/
  486. #if ANSI_C
  487. int
  488. bwb_stripcr( char *s )
  489. #else
  490. int
  491. bwb_stripcr( s )
  492. char *s;
  493. #endif
  494. {
  495. char *p;
  496. p = s;
  497. while ( *p != 0 )
  498. {
  499. switch( *p )
  500. {
  501. case '\r':
  502. case '\n':
  503. *p = 0;
  504. return TRUE;
  505. }
  506. ++p;
  507. }
  508. *p = 0;
  509. return TRUE;
  510. }
  511. /***************************************************************
  512. FUNCTION: is_numconst()
  513. DESCRIPTION: This function reads the string in <buffer>
  514. and returns TRUE if it is a numerical
  515. constant and FALSE if it is not. At
  516. this point, only decimal (base 10)
  517. constants are detected.
  518. ***************************************************************/
  519. #if ANSI_C
  520. int
  521. is_numconst( char *buffer )
  522. #else
  523. int
  524. is_numconst( buffer )
  525. char *buffer;
  526. #endif
  527. {
  528. char *p;
  529. #if INTENSIVE_DEBUG
  530. sprintf( bwb_ebuf, "in is_numconst(): received string <%s>.", buffer );
  531. bwb_debug( bwb_ebuf );
  532. #endif
  533. /* Return FALSE for empty buffer */
  534. if ( buffer[ 0 ] == '\0' )
  535. {
  536. return FALSE;
  537. }
  538. /* else check digits */
  539. p = buffer;
  540. while( *p != '\0' )
  541. {
  542. switch( *p )
  543. {
  544. case '0':
  545. case '1':
  546. case '2':
  547. case '3':
  548. case '4':
  549. case '5':
  550. case '6':
  551. case '7':
  552. case '8':
  553. case '9':
  554. break;
  555. default:
  556. return FALSE;
  557. }
  558. ++p;
  559. }
  560. /* only numerical characters detected */
  561. return TRUE;
  562. }
  563. /***************************************************************
  564. FUNCTION: bwb_numseq()
  565. DESCRIPTION: This function reads in a sequence of
  566. numbers (e.g., "10-120"), returning
  567. the first and last numbers in the sequence
  568. in the integers pointed to by 'start' and
  569. 'end'.
  570. ***************************************************************/
  571. #if ANSI_C
  572. int
  573. bwb_numseq( char *buffer, int *start, int *end )
  574. #else
  575. int
  576. bwb_numseq( buffer, start, end )
  577. char *buffer;
  578. int *start;
  579. int *end;
  580. #endif
  581. {
  582. register int b, n;
  583. int numbers;
  584. static char *tbuf;
  585. static int init = FALSE;
  586. /* get memory for temporary buffer if necessary */
  587. if ( init == FALSE )
  588. {
  589. init = TRUE;
  590. if ( ( tbuf = calloc( MAXSTRINGSIZE + 1, sizeof( char ) )) == NULL )
  591. {
  592. #if PROG_ERRORS
  593. bwb_error( "in bwb_numseq(): failed to find memory for tbuf" );
  594. #else
  595. bwb_error( err_getmem );
  596. #endif
  597. }
  598. }
  599. if ( buffer[ 0 ] == 0 )
  600. {
  601. *start = *end = 0;
  602. return FALSE;
  603. }
  604. numbers = n = b = 0;
  605. tbuf[ 0 ] = 0;
  606. while( TRUE )
  607. {
  608. switch( buffer[ b ] )
  609. {
  610. case 0: /* end of string */
  611. case '\n':
  612. case '\r':
  613. if ( n > 0 )
  614. {
  615. if ( numbers == 0 )
  616. {
  617. *end = 0;
  618. *start = atoi( tbuf );
  619. ++numbers;
  620. }
  621. else
  622. {
  623. *end = atoi( tbuf );
  624. return TRUE;
  625. }
  626. }
  627. else
  628. {
  629. if ( numbers == 0 )
  630. {
  631. *start = *end = 0;
  632. }
  633. else if ( numbers == 1 )
  634. {
  635. *end = 0;
  636. }
  637. else if ( ( numbers == 2 ) && ( tbuf[ 0 ] == 0 ))
  638. {
  639. *end = 0;
  640. }
  641. }
  642. return TRUE;
  643. #ifdef ALLOWWHITESPACE
  644. case ' ': /* whitespace */
  645. case '\t':
  646. #endif
  647. case '-': /* or skip to next number */
  648. if ( n > 0 )
  649. {
  650. if ( numbers == 0 )
  651. {
  652. *start = atoi( tbuf );
  653. ++numbers;
  654. }
  655. else
  656. {
  657. *end = atoi( tbuf );
  658. return TRUE;
  659. }
  660. }
  661. ++b;
  662. n = 0;
  663. break;
  664. case '0':
  665. case '1':
  666. case '2':
  667. case '3':
  668. case '4':
  669. case '5':
  670. case '6':
  671. case '7':
  672. case '8':
  673. case '9':
  674. tbuf[ n ] = buffer[ b ];
  675. ++n;
  676. tbuf[ n ] = 0;
  677. ++b;
  678. break;
  679. default:
  680. #if PROG_ERRORS
  681. sprintf( bwb_ebuf,
  682. "ERROR: character <%c> unexpected in numerical sequence",
  683. buffer[ b ] );
  684. ++b;
  685. bwb_error( bwb_ebuf );
  686. #else
  687. bwb_error( err_syntax );
  688. #endif
  689. break;
  690. }
  691. }
  692. }
  693. /***************************************************************
  694. FUNCTION: bwb_freeline()
  695. DESCRIPTION: This function frees memory associated
  696. with a program line in memory.
  697. ***************************************************************/
  698. #if ANSI_C
  699. int
  700. bwb_freeline( struct bwb_line *l )
  701. #else
  702. int
  703. bwb_freeline( l )
  704. struct bwb_line *l;
  705. #endif
  706. {
  707. /* free arguments if there are any */
  708. free( l );
  709. return TRUE;
  710. }
  711. /***************************************************************
  712. FUNCTION: int_qmdstr()
  713. DESCRIPTION: This function returns a string delimited
  714. by quotation marks.
  715. ***************************************************************/
  716. #if ANSI_C
  717. int
  718. int_qmdstr( char *buffer_a, char *buffer_b )
  719. #else
  720. int
  721. int_qmdstr( buffer_a, buffer_b )
  722. char *buffer_a;
  723. char *buffer_b;
  724. #endif
  725. {
  726. char *a, *b;
  727. a = buffer_a;
  728. ++a; /* advance beyond quotation mark */
  729. b = buffer_b;
  730. while( *a != '\"' )
  731. {
  732. *b = *a;
  733. ++a;
  734. ++b;
  735. *b = '\0';
  736. }
  737. return TRUE;
  738. }
  739. /***************************************************************
  740. FUNCTION: is_eol()
  741. DESCRIPTION: This function determines whether the buffer
  742. is at the end of a line.
  743. ***************************************************************/
  744. #if ANSI_C
  745. extern int
  746. is_eol( char *buffer, int *position )
  747. #else
  748. int
  749. is_eol( buffer, position )
  750. char *buffer;
  751. int *position;
  752. #endif
  753. {
  754. adv_ws( buffer, position );
  755. #if INTENSIVE_DEBUG
  756. sprintf( bwb_ebuf, "in is_eol(): character is <0x%x> = <%c>",
  757. buffer[ *position ], buffer[ *position ] );
  758. bwb_debug( bwb_ebuf );
  759. #endif
  760. switch( buffer[ *position ] )
  761. {
  762. case '\0':
  763. case '\n':
  764. case '\r':
  765. #if MULTISEG_LINES
  766. case ':':
  767. #endif
  768. return TRUE;
  769. default:
  770. return FALSE;
  771. }
  772. }
  773.