home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / bwbasic / part06 < prev    next >
Encoding:
Text File  |  1992-11-03  |  59.6 KB  |  2,078 lines

  1. Newsgroups: comp.sources.misc
  2. From: tcamp@acpub.duke.edu (Ted A. Campbell)
  3. Subject:  v33i042:  bwbasic - Bywater BASIC interpreter version 1.10, Part06/11
  4. Message-ID: <1992Nov5.035946.17726@sparky.imd.sterling.com>
  5. X-Md4-Signature: c722602896b74bad0a1249f3582b3abd
  6. Date: Thu, 5 Nov 1992 03:59:46 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tcamp@acpub.duke.edu (Ted A. Campbell)
  10. Posting-number: Volume 33, Issue 42
  11. Archive-name: bwbasic/part06
  12. Environment: ANSI-C
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  bwb_exp.c bwbasic.doc
  19. # Wrapped by kent@sparky on Wed Nov  4 21:34:25 1992
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 6 (of 11)."'
  23. if test -f 'bwb_exp.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'bwb_exp.c'\"
  25. else
  26.   echo shar: Extracting \"'bwb_exp.c'\" \(40302 characters\)
  27.   sed "s/^X//" >'bwb_exp.c' <<'END_OF_FILE'
  28. X/****************************************************************
  29. X
  30. X        bwb_exp.c       Expression Parser
  31. X                        for Bywater BASIC Interpreter
  32. X
  33. X                        Copyright (c) 1992, Ted A. Campbell
  34. X
  35. X                        Bywater Software
  36. X                        P. O. Box 4023
  37. X                        Duke Station
  38. X                        Durham, NC  27706
  39. X
  40. X                        email: tcamp@acpub.duke.edu
  41. X
  42. X        Copyright and Permissions Information:
  43. X
  44. X        All U.S. and international copyrights are claimed by the
  45. X        author. The author grants permission to use this code
  46. X        and software based on it under the following conditions:
  47. X        (a) in general, the code and software based upon it may be
  48. X        used by individuals and by non-profit organizations; (b) it
  49. X        may also be utilized by governmental agencies in any country,
  50. X        with the exception of military agencies; (c) the code and/or
  51. X        software based upon it may not be sold for a profit without
  52. X        an explicit and specific permission from the author, except
  53. X        that a minimal fee may be charged for media on which it is
  54. X        copied, and for copying and handling; (d) the code must be
  55. X        distributed in the form in which it has been released by the
  56. X        author; and (e) the code and software based upon it may not
  57. X        be used for illegal activities.
  58. X
  59. X****************************************************************/
  60. X
  61. X#include <stdio.h>
  62. X#include <stdlib.h>
  63. X#include <string.h>
  64. X#include <ctype.h>
  65. X#include <math.h>
  66. X
  67. X#include "bwbasic.h"
  68. X#include "bwb_mes.h"
  69. X
  70. Xint exp_esc = 0;                        /* expression stack counter */
  71. X
  72. X/***************************************************************
  73. X
  74. X        FUNCTION:   bwb_exp()
  75. X
  76. X        DESCRIPTION:  This is the function by which the expression
  77. X        parser is called.
  78. X
  79. X***************************************************************/
  80. X
  81. Xstruct exp_ese *
  82. Xbwb_exp( char *expression, int assignment, int *position )
  83. X   {
  84. X   struct exp_ese *rval;            /* return value */
  85. X   int entry_level, main_loop, adv_loop, err_condition;
  86. X   char *e;                                     /* pointer to current string */
  87. X   int r;                                       /* return value from functions */
  88. X   register int c;                              /* quick counter */
  89. X
  90. X   #if INTENSIVE_DEBUG
  91. X   sprintf( bwb_ebuf, "in bwb_exp(): expression <%s> assignment <%d> level <%d>",
  92. X      & ( expression[ *position ] ), assignment, exp_esc );
  93. X   bwb_debug( bwb_ebuf );
  94. X   #endif
  95. X
  96. X   /* save the entry level of the expression stack in order to
  97. X      check it at the end of this function */
  98. X
  99. X   entry_level = exp_esc;
  100. X   err_condition = FALSE;
  101. X
  102. X   /* advance past whitespace or beginningg of line segment */
  103. X
  104. X   if ( expression[ *position ] == ':' )
  105. X      {
  106. X      ++( *position );
  107. X      }
  108. X   adv_ws( expression, position );
  109. X   if ( expression[ *position ] == ':' )
  110. X      {
  111. X      ++( *position );
  112. X      adv_ws( expression, position );
  113. X      }
  114. X
  115. X   /* increment the expression stack counter to get a new level */
  116. X
  117. X   inc_esc();
  118. X
  119. X   /* check to be sure there is a legitimate expression
  120. X      and set initial parameters for the main loop */
  121. X
  122. X   adv_loop = TRUE;
  123. X   while( adv_loop == TRUE )
  124. X      {
  125. X      switch( expression[ *position ] )
  126. X         {
  127. X         case ' ':                           /* whitespace */
  128. X         case '\t':
  129. X            ++(*position);
  130. X            break;
  131. X         case '\0':                          /* end of string */
  132. X         case '\r':
  133. X         case '\n':
  134. X            main_loop = adv_loop = FALSE;    /* break out of loop */
  135. X            break;
  136. X         default:
  137. X            adv_loop = FALSE;
  138. X            main_loop = TRUE;
  139. X            exp_es[ exp_esc ].pos_adv = 0;
  140. X            break;
  141. X         }
  142. X      }
  143. X
  144. X   /* main parsing loop */
  145. X
  146. X   while ( main_loop == TRUE )
  147. X      {
  148. X
  149. X      /* set variable <e> to the start of the expression */
  150. X
  151. X      e = &( expression[ *position ] );
  152. X
  153. X      #if INTENSIVE_DEBUG
  154. X      sprintf( bwb_ebuf, "in bwb_exp(): main loop, level <%d> element <%s> ",
  155. X         exp_esc, e );
  156. X      bwb_debug( bwb_ebuf );
  157. X      #endif
  158. X
  159. X      /* detect the operation required at this level */
  160. X
  161. X      exp_es[ exp_esc ].operation = exp_findop( e );
  162. X
  163. X      #if INTENSIVE_DEBUG
  164. X      sprintf( bwb_ebuf, "in bwb_exp(): exp_findop() returned <%d>",
  165. X         exp_es[ exp_esc ].operation );
  166. X      bwb_debug( bwb_ebuf );
  167. X      #endif
  168. X
  169. X      /* perform actions specific to the operation */
  170. X
  171. X      switch( exp_es[ exp_esc ].operation )
  172. X         {
  173. X         case OP_ERROR:
  174. X            main_loop = FALSE;
  175. X            err_condition = TRUE;
  176. X            break;
  177. X         case OP_TERMINATE:
  178. X            main_loop = FALSE;
  179. X            /* *position += 1; */
  180. X            dec_esc();
  181. X            break;
  182. X         case OP_STRJOIN:                  /* string join or tab */
  183. X         case OP_STRTAB:
  184. X            main_loop = FALSE;
  185. X            dec_esc();
  186. X            break;
  187. X         case OP_ADD:                      /* in the case of any numerical operation, */
  188. X         case OP_SUBTRACT:
  189. X         case OP_MULTIPLY:
  190. X         case OP_DIVIDE:
  191. X         case OP_MODULUS:
  192. X         case OP_EXPONENT:
  193. X         case OP_INTDIVISION:
  194. X         case OP_GREATERTHAN:
  195. X         case OP_LESSTHAN:
  196. X         case OP_GTEQ:
  197. X         case OP_LTEQ:
  198. X         case OP_NOTEQUAL:
  199. X         case OP_NOT:
  200. X         case OP_AND:
  201. X         case OP_OR:
  202. X         case OP_XOR:
  203. X         case OP_IMPLIES:
  204. X         case OP_EQUIV:
  205. X
  206. X            #if INTENSIVE_DEBUG
  207. X            sprintf( bwb_ebuf, "in bwb_exp(): operator detected." );
  208. X            bwb_debug( bwb_ebuf );
  209. X            #endif
  210. X
  211. X            exp_es[ exp_esc ].pos_adv = -1;             /* set to strange number */
  212. X
  213. X            /* cycle through operator table to find match */
  214. X
  215. X            for ( c = 0; c < N_OPERATORS; ++c )
  216. X               {
  217. X               if ( exp_ops[ c ].operation == exp_es[ exp_esc ].operation )
  218. X                  {
  219. X                  exp_es[ exp_esc ].pos_adv = strlen( exp_ops[ c ].symbol );
  220. X                  }
  221. X               }
  222. X
  223. X            if ( exp_es[ exp_esc ].pos_adv == -1 )      /* was a match found? */
  224. X               {
  225. X               exp_es[ exp_esc ].pos_adv = 0;           /* no -- set to 0 */
  226. X               }
  227. X            break;                         /* and move on */
  228. X
  229. X         case OP_EQUALS:
  230. X
  231. X            #if INTENSIVE_DEBUG
  232. X            sprintf( bwb_ebuf, "in bwb_exp(): equal sign detected." );
  233. X            bwb_debug( bwb_ebuf );
  234. X            #endif
  235. X
  236. X            if ( assignment == TRUE )
  237. X               {
  238. X               exp_es[ exp_esc ].operation = OP_ASSIGN;
  239. X               }
  240. X            exp_es[ exp_esc ].pos_adv = 1;
  241. X            break;
  242. X
  243. X         case PARENTHESIS:
  244. X            r = exp_paren( e );
  245. X            break;
  246. X         case CONST_STRING:
  247. X            r = exp_strconst( e );
  248. X            break;
  249. X         case CONST_NUMERICAL:
  250. X            r = exp_numconst( e );
  251. X        #if INTENSIVE_DEBUG
  252. X            sprintf( bwb_ebuf, "in bwb_exp(): return from exp_numconst(), r = <%d>",
  253. X               r );
  254. X            bwb_debug( bwb_ebuf );
  255. X            #endif
  256. X            break;
  257. X
  258. X         case FUNCTION:
  259. X
  260. X            #if INTENSIVE_DEBUG
  261. X            sprintf( bwb_ebuf, "in bwb_exp(): calling exp_function(), expression <%s>",
  262. X               e );
  263. X            bwb_debug( bwb_ebuf );
  264. X            #endif
  265. X
  266. X            r = exp_function( e );
  267. X            break;
  268. X
  269. X         case VARIABLE:
  270. X            r = exp_variable( e );
  271. X            break;
  272. X         default:
  273. X            err_condition = TRUE;
  274. X            main_loop = FALSE;
  275. X            #if PROG_ERRORS
  276. X            sprintf( bwb_ebuf, "in bwb_exp.c:bwb_exp(): unidentified operation (%d).",
  277. X               exp_es[ exp_esc ].operation );
  278. X            bwb_error( bwb_ebuf );
  279. X            #else
  280. X            bwb_error( err_syntax );
  281. X            #endif
  282. X            break;
  283. X         }
  284. X
  285. X      /* increment *position counter based on previous actions */
  286. X
  287. X      *position += exp_es[ exp_esc ].pos_adv;
  288. X      exp_es[ exp_esc ].pos_adv = 0;            /* reset advance counter */
  289. X
  290. X      #if INTENSIVE_DEBUG
  291. X      sprintf( bwb_ebuf, "in bwb_exp(): advanced position; r <%d> err_c <%d>",
  292. X         r, err_condition );
  293. X      bwb_debug( bwb_ebuf );
  294. X      #endif
  295. X
  296. X      #if INTENSIVE_DEBUG
  297. X      if ( exp_es[ exp_esc ].operation == OP_EQUALS )
  298. X         {
  299. X         sprintf( bwb_ebuf, "in bwb_exp(): with OP_EQUALS: finished case" );
  300. X         bwb_debug( bwb_ebuf );
  301. X         }
  302. X      #endif
  303. X
  304. X      /* check for end of string */
  305. X
  306. X      adv_loop = TRUE;
  307. X      while( adv_loop == TRUE )
  308. X         {
  309. X         switch( expression[ *position ] )
  310. X            {
  311. X            case ' ':                           /* whitespace */
  312. X            case '\t':
  313. X               ++(*position);
  314. X               break;
  315. X            case '\0':                          /* end of string */
  316. X            case '\r':
  317. X            case '\n':
  318. X            case ':':
  319. X               main_loop = adv_loop = FALSE;    /* break out of loop */
  320. X               break;
  321. X            default:
  322. X               adv_loop = FALSE;
  323. X               break;
  324. X            }
  325. X         }
  326. X
  327. X      /* get a new stack level before looping */
  328. X
  329. X      if ( main_loop == TRUE )
  330. X         {
  331. X         r = inc_esc();
  332. X         #if INTENSIVE_DEBUG
  333. X         sprintf( bwb_ebuf, "in bwb_exp(): increment esc, r <%d>, err_c <%d>",
  334. X            r, err_condition );
  335. X         bwb_debug( bwb_ebuf );
  336. X         #endif
  337. X         }
  338. X
  339. X      /* check for error return */
  340. X
  341. X      if ( r == OP_ERROR )
  342. X         {
  343. X         #if INTENSIVE_DEBUG
  344. X         sprintf( bwb_ebuf, "in bwb_exp(): found r == OP_ERROR." );
  345. X         bwb_debug( bwb_ebuf );
  346. X         #endif
  347. X         main_loop = FALSE;
  348. X         err_condition = TRUE;
  349. X         }
  350. X      else
  351. X         {
  352. X         r = TRUE;
  353. X         }
  354. X
  355. X      }                                 /* end of main parsing loop */
  356. X
  357. X   #if INTENSIVE_DEBUG
  358. X   sprintf( bwb_ebuf, "in bwb_exp(): breakout from main parsing loop, r <%d> err_c <%d>",
  359. X      r, err_condition );
  360. X   bwb_debug( bwb_ebuf );
  361. X   #endif
  362. X
  363. X   /* check error condition */
  364. X
  365. X   if ( err_condition == TRUE )
  366. X      {
  367. X
  368. X      #if INTENSIVE_DEBUG
  369. X      sprintf( bwb_ebuf, "ERROR: error detected in expression parser" );
  370. X      bwb_debug( bwb_ebuf );
  371. X      #endif
  372. X
  373. X      /* decrement the expression stack counter until it matches entry_level */
  374. X
  375. X      while( exp_esc > entry_level )
  376. X         {
  377. X         dec_esc();
  378. X         }
  379. X
  380. X      }
  381. X
  382. X   /* no error; normal exit from function */
  383. X
  384. X   else
  385. X      {
  386. X
  387. X      /* are any more operations needed? if we are still at entry level,
  388. X         then they are not */
  389. X
  390. X      /* try operations */
  391. X
  392. X      exp_operation( entry_level );
  393. X
  394. X      /* see what is on top of the stack */
  395. X
  396. X      if ( exp_esc > ( entry_level + 1 ))
  397. X         {
  398. X         switch( exp_es[ exp_esc ].operation )
  399. X            {
  400. X            case OP_STRJOIN:
  401. X               if ( exp_esc != ( entry_level + 2 ))
  402. X                  {
  403. X                  #if PROG_ERRORS
  404. X                  sprintf( bwb_ebuf, "in bwb_exp(): OP_STRJOIN in wrong position." );
  405. X                  bwb_error( bwb_ebuf );
  406. X                  #else
  407. X                  bwb_error( err_syntax );
  408. X                  #endif
  409. X                  }
  410. X               break;
  411. X            default:
  412. X               #if PROG_ERRORS
  413. X               sprintf( bwb_ebuf, "in bwb_exp(): incomplete expression." );
  414. X               bwb_error( bwb_ebuf );
  415. X               #else
  416. X               bwb_error( err_syntax );
  417. X               #endif
  418. X               break;
  419. X            }
  420. X
  421. X         /* decrement the expression stack counter */
  422. X
  423. X         #if INTENSIVE_DEBUG
  424. X         sprintf( bwb_ebuf, "in bwb_exp(): before dec_esc type is <%c>",
  425. X            exp_es[ exp_esc ].type );
  426. X         bwb_debug( bwb_ebuf );
  427. X         #endif
  428. X
  429. X         dec_esc();
  430. X
  431. X         }
  432. X
  433. X      /* assign rvar to the variable for the current level */
  434. X
  435. X      rval = &( exp_es[ exp_esc ] );
  436. X
  437. X      /* decrement the expression stack counter */
  438. X
  439. X      dec_esc();
  440. X
  441. X      /* check the current level before exit */
  442. X
  443. X      if ( entry_level != exp_esc )
  444. X         {
  445. X         #if PROG_ERRORS
  446. X         sprintf( bwb_ebuf, "in bwb_exp(): exit stack level (%d) does not match entry stack level (%d)",
  447. X            exp_esc, entry_level );
  448. X         bwb_error( bwb_ebuf );
  449. X         #else
  450. X         bwb_error( err_overflow );
  451. X         #endif
  452. X         }
  453. X
  454. X      }
  455. X
  456. X   /* return a pointer to the last stack level */
  457. X
  458. X   return rval;
  459. X
  460. X   }
  461. X
  462. X/***************************************************************
  463. X
  464. X        FUNCTION:   exp_findop()
  465. X
  466. X        DESCRIPTION:  This function reads the expression to find
  467. X        what operation is required at its stack level.
  468. X
  469. X***************************************************************/
  470. X
  471. Xint
  472. Xexp_findop( char *expression )
  473. X   {
  474. X   char *pointer;                               /* pointer to start of string */
  475. X   register int c;                              /* character counter */
  476. X   int carry_on;                                /* boolean: control while loop */
  477. X   int rval;                                    /* return value */
  478. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  479. X
  480. X   #if INTENSIVE_DEBUG
  481. X   sprintf( bwb_ebuf, "in exp_findop(): received <%s>", expression );
  482. X   bwb_debug( bwb_ebuf );
  483. X   #endif
  484. X
  485. X   /* set return value to OP_NULL initially */
  486. X
  487. X   rval = OP_NULL;
  488. X
  489. X   /* assign local pointer to expression to begin reading */
  490. X
  491. X   pointer = expression;
  492. X
  493. X   /* advance to the first significant character */
  494. X
  495. X   carry_on = TRUE;
  496. X   while ( carry_on == TRUE )
  497. X      {
  498. X      switch( *pointer )
  499. X         {
  500. X         case ' ':                              /* whitespace */
  501. X         case '\t':
  502. X            ++pointer;                          /* increment the pointer */
  503. X            break;                              /* and move on */
  504. X         default:
  505. X            carry_on = FALSE;                   /* break out of while loop */
  506. X            break;
  507. X         }
  508. X      }
  509. X
  510. X   /* we now have the first significant character and can begin parsing */
  511. X
  512. X   /* check the first character for an indication of a parenthetical
  513. X      expression, a string constant, or a numerical constant that begins
  514. X      with a digit (numerical constants beginning with a plus or minus
  515. X      sign or hex/octal/binary constants will have to be detected by
  516. X      exp_isnc() */
  517. X
  518. X   carry_on = TRUE;
  519. X   switch ( *pointer )
  520. X      {
  521. X      case '\"':                /* this should indicate a string constant */
  522. X         rval = CONST_STRING;
  523. X         break;
  524. X      case '(':                 /* this will indicate a simple parenthetical expression */
  525. X         rval = PARENTHESIS;
  526. X         break;
  527. X      case ':':                 /* terminate processing */
  528. X         rval = OP_TERMINATE;
  529. X         break;
  530. X      case '0':                 /* these will indicate a numerical constant */
  531. X      case '1':
  532. X      case '2':
  533. X      case '3':
  534. X      case '4':
  535. X      case '5':
  536. X      case '6':
  537. X      case '7':
  538. X      case '8':
  539. X      case '9':
  540. X      case '.':
  541. X      case '&':                 /* designator for hex or octal constant */
  542. X         rval = CONST_NUMERICAL;
  543. X         break;
  544. X      }
  545. X
  546. X   #if INTENSIVE_DEBUG
  547. X   sprintf( bwb_ebuf, "in exp_findop(): rval pos 1 is <%d>", rval );
  548. X   bwb_debug( bwb_ebuf );
  549. X   #endif
  550. X
  551. X   /* string constants, numerical constants, open parentheses, and
  552. X      the plus and minus operators have been checked at this point;
  553. X      but if the return value is still OP_NULL, other possibilities
  554. X      must be checked, namely, other operators, function names, and
  555. X      variable names */
  556. X
  557. X   /* get a character string to be interpreted */
  558. X
  559. X   if ( rval == OP_NULL )
  560. X      {
  561. X
  562. X      carry_on = TRUE;
  563. X      c = 0;
  564. X      tbuf[ c ] = *pointer;
  565. X      ++c;
  566. X      tbuf[ c ] = '\0';
  567. X      while( carry_on == TRUE )
  568. X         {
  569. X         switch( pointer[ c ] )
  570. X            {
  571. X            case ' ':                           /* whitespace */
  572. X            case '\t':
  573. X            case '(':
  574. X            case ')':
  575. X            case ',':
  576. X            case ';':
  577. X            case '\0':
  578. X            case '\n':
  579. X            case '\r':
  580. X               carry_on = FALSE;
  581. X               break;
  582. X            default:
  583. X               tbuf[ c ] = pointer[ c ];
  584. X               ++c;
  585. X               tbuf[ c ] = '\0';
  586. X               break;
  587. X            }
  588. X         }
  589. X
  590. X      }
  591. X
  592. X   /* check for a BASIC command */
  593. X
  594. X   if ( rval == OP_NULL )
  595. X      {
  596. X      rval = exp_iscmd( tbuf );
  597. X      }
  598. X
  599. X   /* check for numerical constant */
  600. X
  601. X   if ( rval == OP_NULL )
  602. X      {
  603. X      rval = exp_isnc( tbuf );
  604. X      }
  605. X
  606. X   /* check for other operators */
  607. X
  608. X   if ( rval == OP_NULL )
  609. X      {
  610. X      rval = exp_isop( tbuf );
  611. X      }
  612. X
  613. X   /* check for function name */
  614. X
  615. X   if ( rval == OP_NULL )
  616. X      {
  617. X      rval = exp_isfn( tbuf );
  618. X      }
  619. X
  620. X   /* last: check for variable name, and assign it if there
  621. X      is not already one */
  622. X
  623. X   if ( rval == OP_NULL )
  624. X      {
  625. X      rval = exp_isvn( tbuf );
  626. X      }
  627. X
  628. X   /* return the value assigned (or OP_NULL if none assigned) */
  629. X
  630. X   return rval;
  631. X
  632. X   }
  633. X
  634. X/***************************************************************
  635. X
  636. X        FUNCTION:   exp_isnc()
  637. X
  638. X        DESCRIPTION:  This function reads the expression to find
  639. X        if a logical or mathematical operation is required at
  640. X        this point.
  641. X
  642. X***************************************************************/
  643. X
  644. Xint
  645. Xexp_isnc( char *expression )
  646. X   {
  647. X
  648. X   switch( expression[ 0 ] )
  649. X      {
  650. X      case '0':                 /* these will indicate a numerical constant */
  651. X      case '1':
  652. X      case '2':
  653. X      case '3':
  654. X      case '4':
  655. X      case '5':
  656. X      case '6':
  657. X      case '7':
  658. X      case '8':
  659. X      case '9':
  660. X      case '&':                 /* indicator for hex or octal constant */
  661. X         return CONST_NUMERICAL;
  662. X      case '+':
  663. X      case '-':
  664. X
  665. X         /* if the previous stack level was a numerical value or a string,
  666. X            then this is certainly not one; return OP_NULL here
  667. X            and let the next function call to exp_isop() determine
  668. X            the (plus or minus) operator */
  669. X
  670. X         if (  ( exp_es[ exp_esc - 1 ].operation == NUMBER )
  671. X            || ( exp_es[ exp_esc - 1 ].operation == VARIABLE )
  672. X            || ( exp_es[ exp_esc - 1 ].operation == CONST_STRING ) )
  673. X            {
  674. X
  675. X            #if INTENSIVE_DEBUG
  676. X            sprintf( bwb_ebuf, "in exp_isnc(): previous function is a number or string" );
  677. X            bwb_debug( bwb_ebuf );
  678. X            #endif
  679. X
  680. X            return OP_NULL;
  681. X            }
  682. X
  683. X         /* similarly, if the previous stack level was a variable
  684. X            with a numerical value (not a string), then this level
  685. X            must be an operator, not a numerical constant */
  686. X
  687. X         if ( ( exp_es[ exp_esc - 1 ].operation == VARIABLE )
  688. X            && ( exp_es[ exp_esc - 1 ].type != STRING ))
  689. X            {
  690. X            return OP_NULL;
  691. X            }
  692. X
  693. X         /* failing these tests, the argument must be a numerical
  694. X            constant preceded by a plus or minus sign */
  695. X
  696. X         return CONST_NUMERICAL;
  697. X
  698. X      default:
  699. X         return OP_NULL;
  700. X      }
  701. X
  702. X   }
  703. X
  704. X/***************************************************************
  705. X
  706. X        FUNCTION:   exp_isop()
  707. X
  708. X        DESCRIPTION:  This function reads the expression to find
  709. X        if a logical or mathematical operation is required at
  710. X        this point.
  711. X
  712. X        This function presupposes that a numerical constant with
  713. X        affixed plus or minus sign has been ruled out.
  714. X
  715. X***************************************************************/
  716. X
  717. Xint
  718. Xexp_isop( char *expression )
  719. X   {
  720. X   register int c;                              /* counter */
  721. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  722. X
  723. X   /* first convert the expression to upper-case so that comparisons
  724. X      will work */
  725. X
  726. X   for ( c = 0; expression[ c ] != '\0'; ++c )
  727. X      {
  728. X      if ( islower( expression[ c ] ))
  729. X         {
  730. X         tbuf[ c ] = toupper( expression[ c ] );
  731. X         }
  732. X      else
  733. X         {
  734. X         tbuf[ c ] = expression[ c ];
  735. X         }
  736. X      tbuf[ c + 1 ] = '\0';
  737. X      }
  738. X
  739. X   #if INTENSIVE_DEBUG
  740. X   sprintf( bwb_ebuf, "in exp_isop(): expression is <%s>", tbuf );
  741. X   bwb_debug( bwb_ebuf );
  742. X   #endif
  743. X
  744. X   /* compare the initial characters of the string with the table
  745. X      of operators */
  746. X
  747. X   for ( c = 0; c < N_OPERATORS; ++c )
  748. X      {
  749. X      if ( strncmp( tbuf, exp_ops[ c ].symbol,
  750. X         (size_t) strlen( exp_ops[ c ].symbol ) ) == 0 )
  751. X         {
  752. X
  753. X         #if INTENSIVE_DEBUG
  754. X         sprintf( bwb_ebuf, "in exp_isop(): match <%s>, number <%d>.",
  755. X            exp_ops[ c ].symbol, c );
  756. X         bwb_debug( bwb_ebuf );
  757. X         #endif
  758. X
  759. X         return exp_ops[ c ].operation;
  760. X         }
  761. X      }
  762. X
  763. X   /* search failed; return OP_NULL */
  764. X
  765. X   return OP_NULL;
  766. X
  767. X   }
  768. X
  769. X/***************************************************************
  770. X
  771. X        FUNCTION:   exp_iscmd()
  772. X
  773. X        DESCRIPTION:  This function reads the expression to find
  774. X        if a BASIC command name is present; if so, it returns
  775. X        OP_TERMINATE to terminate expression parsing.  This is
  776. X        critical, for example, in parsing a conditional following
  777. X        IF where THEN, ELSE, and other BASIC commands may follow.
  778. X
  779. X***************************************************************/
  780. X
  781. Xint
  782. Xexp_iscmd( char *expression )
  783. X   {
  784. X   register int n;
  785. X   char tbuf[ MAXSTRINGSIZE + 1 ];
  786. X
  787. X   /* capitalize the expression */
  788. X
  789. X   for ( n = 0; expression[ n ] != '\0'; ++n )
  790. X      {
  791. X      if ( n >= MAXARGSIZE )
  792. X         {
  793. X         #if PROG_ERRORS
  794. X         sprintf( bwb_ebuf, "Maximum arguments size exceeded." );
  795. X         bwb_error( bwb_ebuf );
  796. X         #else
  797. X         bwb_error( err_overflow );
  798. X         #endif
  799. X         }
  800. X      if ( islower( expression[ n ] ) != FALSE )
  801. X         {
  802. X         tbuf[ n ] = toupper( expression[ n ] );
  803. X         }
  804. X      else
  805. X         {
  806. X         tbuf[ n ] = expression[ n ];
  807. X         }
  808. X      tbuf[ n + 1 ] = '\0';
  809. X      }
  810. X
  811. X   #if INTENSIVE_DEBUG
  812. X   sprintf( bwb_ebuf, "in exp_iscmd(): expression received <%s>, converted <%s>.",
  813. X      expression, tbuf );
  814. X   bwb_debug( bwb_ebuf );
  815. X   #endif
  816. X
  817. X   /* first check for THEN or ELSE statements */
  818. X
  819. X   if ( strcmp( tbuf, "THEN" ) == 0 )
  820. X      {
  821. X      #if INTENSIVE_DEBUG
  822. X      sprintf( bwb_ebuf, "in exp_iscmd(): match found, <%s>",
  823. X         tbuf );
  824. X      bwb_debug( bwb_ebuf );
  825. X      #endif
  826. X      return OP_TERMINATE;
  827. X      }
  828. X
  829. X   if ( strcmp( tbuf, "ELSE" ) == 0 )
  830. X      {
  831. X      #if INTENSIVE_DEBUG
  832. X      sprintf( bwb_ebuf, "in exp_iscmd(): match found, <%s>",
  833. X         tbuf );
  834. X      bwb_debug( bwb_ebuf );
  835. X      #endif
  836. X      return OP_TERMINATE;
  837. X      }
  838. X
  839. X   /* run through the command table and search for a match */
  840. X
  841. X   for ( n = 0; n < COMMANDS; ++n )
  842. X      {
  843. X      if ( strcmp( tbuf, bwb_cmdtable[ n ].name ) == 0 )
  844. X         {
  845. X         #if INTENSIVE_DEBUG
  846. X         sprintf( bwb_ebuf, "in exp_iscmd(): match found, <%s>",
  847. X            tbuf );
  848. X         bwb_debug( bwb_ebuf );
  849. X         #endif
  850. X         return OP_TERMINATE;
  851. X         }
  852. X      #if INTENSIVE_DEBUG
  853. X      else
  854. X         {
  855. X         sprintf( bwb_ebuf, "in exp_iscmd(): No match, <%s> and <%s>; returns %d",
  856. X            tbuf, bwb_cmdtable[ n ].name,
  857. X            strcmp( tbuf, bwb_cmdtable[ n ].name ) );
  858. X         bwb_debug( bwb_ebuf );
  859. X         }
  860. X      #endif
  861. X      }
  862. X
  863. X   /* search failed, return NULL */
  864. X
  865. X   return OP_NULL;
  866. X
  867. X   }
  868. X
  869. X/***************************************************************
  870. X
  871. X        FUNCTION:   exp_isfn()
  872. X
  873. X        DESCRIPTION:  This function reads the expression to find
  874. X        if a function name is present at this point.
  875. X
  876. X***************************************************************/
  877. X
  878. Xint
  879. Xexp_isfn( char *expression )
  880. X   {
  881. X
  882. X   if ( fnc_find( expression ) == NULL )
  883. X      {
  884. X      #if INTENSIVE_DEBUG
  885. X      sprintf( bwb_ebuf, "in exp_isfn(): failed to find function <%s>",
  886. X         expression );
  887. X      bwb_debug( bwb_ebuf );
  888. X      #endif
  889. X      return OP_NULL;
  890. X      }
  891. X   else
  892. X      {
  893. X      #if INTENSIVE_DEBUG
  894. X      sprintf( bwb_ebuf, "in exp_isfn(): found function <%s>",
  895. X         expression );
  896. X      bwb_debug( bwb_ebuf );
  897. X      #endif
  898. X      return FUNCTION;
  899. X      }
  900. X
  901. X   }
  902. X
  903. X/***************************************************************
  904. X
  905. X        FUNCTION:   exp_isvn()
  906. X
  907. X        DESCRIPTION:  This function reads the expression to find
  908. X        if a variable name at this point.
  909. X
  910. X***************************************************************/
  911. X
  912. Xint
  913. Xexp_isvn( char *expression )
  914. X   {
  915. X
  916. X   exp_getvfname( expression, exp_es[ exp_esc ].string );
  917. X
  918. X   if ( var_find( exp_es[ exp_esc ].string ) == NULL )
  919. X      {
  920. X      #if INTENSIVE_DEBUG
  921. X      sprintf( bwb_ebuf, "in exp_isvn(): failed to find variable <%s>",
  922. X         expression );
  923. X      bwb_debug( bwb_ebuf );
  924. X      #endif
  925. X      return OP_NULL;
  926. X      }
  927. X   else
  928. X      {
  929. X      #if INTENSIVE_DEBUG
  930. X      sprintf( bwb_ebuf, "in exp_isvn(): found variable <%s>",
  931. X         exp_es[ exp_esc ].string );
  932. X      bwb_debug( bwb_ebuf );
  933. X      #endif
  934. X      return VARIABLE;
  935. X      }
  936. X
  937. X   }
  938. X
  939. X/***************************************************************
  940. X
  941. X        FUNCTION:   exp_getvfname()
  942. X
  943. X        DESCRIPTION:  This function reads the expression to find
  944. X        a variable or function name at this point.
  945. X
  946. X***************************************************************/
  947. X
  948. Xint
  949. Xexp_getvfname( char *source, char *destination )
  950. X   {
  951. X   int s_pos, d_pos;                    /* source, destination positions */
  952. X
  953. X   s_pos = d_pos = 0;
  954. X   destination[ 0 ] = '\0';
  955. X   while( source[ s_pos ] != '\0' )
  956. X      {
  957. X
  958. X      /* all aphabetical characters are acceptable */
  959. X
  960. X      if ( isalpha( source[ s_pos ] ) != 0 )
  961. X
  962. X         {
  963. X         destination[ d_pos ] = source[ s_pos ];
  964. X
  965. X         ++d_pos;
  966. X         ++s_pos;
  967. X         destination[ d_pos ] = '\0';
  968. X         }
  969. X
  970. X      /* numerical characters are acceptable but not in the first position */
  971. X
  972. X      else if (( isdigit( source[ s_pos ] ) != 0 ) && ( d_pos != 0 ))
  973. X         {
  974. X         destination[ d_pos ] = source[ s_pos ];
  975. X         ++d_pos;
  976. X         ++s_pos;
  977. X         destination[ d_pos ] = '\0';
  978. X         }
  979. X
  980. X      /* other characters will have to be tried on their own merits */
  981. X
  982. X      else
  983. X         {
  984. X         switch( source[ s_pos ] )
  985. X            {
  986. X
  987. X            case '.':                           /* tolerated non-alphabetical characters */
  988. X
  989. X            case '_':
  990. X               destination[ d_pos ] = source[ s_pos ];
  991. X               ++d_pos;
  992. X               ++s_pos;
  993. X               destination[ d_pos ] = '\0';
  994. X               break;
  995. X
  996. X            case STRING:                        /* terminating characters */
  997. X            case SINGLE:
  998. X            case DOUBLE:
  999. X            case INTEGER:
  1000. X               destination[ d_pos ] = source[ s_pos ];
  1001. X               ++d_pos;
  1002. X               ++s_pos;
  1003. X               destination[ d_pos ] = '\0';
  1004. X
  1005. X               return TRUE;
  1006. X            default:                            /* anything else is non-tolerated */
  1007. X               return FALSE;
  1008. X            }
  1009. X         }
  1010. X      }
  1011. X
  1012. X   #if INTENSIVE_DEBUG
  1013. X   sprintf( bwb_ebuf, "in exp_getvfname(): found name <%s>", destination );
  1014. X   bwb_debug( bwb_ebuf );
  1015. X   #endif
  1016. X
  1017. X   return TRUE;                         /* exit after coming to the end */
  1018. X
  1019. X   }
  1020. X
  1021. X/***************************************************************
  1022. X
  1023. X        FUNCTION:   exp_validarg()
  1024. X
  1025. X        DESCRIPTION:  This function reads the expression to
  1026. X        determine whether it is a valid argument (to be
  1027. X        read recursively by bwb_exp() and passed to a
  1028. X        function.
  1029. X
  1030. X***************************************************************/
  1031. X
  1032. Xint
  1033. Xexp_validarg( char *expression )
  1034. X   {
  1035. X   register int c;
  1036. X
  1037. X   #if INTENSIVE_DEBUG
  1038. X   sprintf( bwb_ebuf, "in exp_validarg(): expression <%s>.",
  1039. X      expression );
  1040. X   bwb_debug( bwb_ebuf );
  1041. X   #endif
  1042. X
  1043. X   c = 0;
  1044. X   while ( TRUE )
  1045. X      {
  1046. X      switch( expression[ c ] )
  1047. X         {
  1048. X         case ' ':
  1049. X         case '\t':
  1050. X            ++c;
  1051. X            break;
  1052. X         case '\0':
  1053. X            return FALSE;
  1054. X         default:
  1055. X            return TRUE;
  1056. X         }
  1057. X      }
  1058. X
  1059. X   }
  1060. X
  1061. X/***************************************************************
  1062. X
  1063. X        FUNCTION:   exp_getdval()
  1064. X
  1065. X        DESCRIPTION:
  1066. X
  1067. X***************************************************************/
  1068. X
  1069. Xdouble
  1070. Xexp_getdval( struct exp_ese *e )
  1071. X   {
  1072. X
  1073. X   /* check for variable */
  1074. X
  1075. X   if ( e->operation == VARIABLE )
  1076. X      {
  1077. X      switch( e->type )
  1078. X         {
  1079. X         case DOUBLE:
  1080. X            return (* var_finddval( e->xvar, e->array_pos ));
  1081. X         case SINGLE:
  1082. X            return (double) (* var_findfval( e->xvar, e->array_pos ));
  1083. X         case INTEGER:
  1084. X            return (double) (* var_findival( e->xvar, e->array_pos ));
  1085. X         default:
  1086. X            bwb_error( err_mismatch );
  1087. X            return (double) 0.0;
  1088. X         }
  1089. X      }
  1090. X
  1091. X   /* must be a numerical value */
  1092. X
  1093. X   if ( e->operation != NUMBER )
  1094. X      {
  1095. X      #if PROG_ERRORS
  1096. X      sprintf( bwb_ebuf, "in exp_getdval(): operation <%d> is not a number",
  1097. X         e->operation );
  1098. X      bwb_error( bwb_ebuf );
  1099. X      #else
  1100. X      bwb_error( err_syntax );
  1101. X      #endif
  1102. X      return (double) 0.0;
  1103. X      }
  1104. X
  1105. X   /* return specific values */
  1106. X
  1107. X   switch( e->type )
  1108. X      {
  1109. X      case SINGLE:
  1110. X         return (double) e->fval;
  1111. X      case INTEGER:
  1112. X         return (double) e->ival;
  1113. X      case DOUBLE:
  1114. X         return e->dval;
  1115. X      default:
  1116. X         #if PROG_ERRORS
  1117. X         sprintf( bwb_ebuf, "in exp_getdval(): type is <%c>",
  1118. X            e->type );
  1119. X         bwb_error( bwb_ebuf );
  1120. X         #else
  1121. X         bwb_error( err_syntax );
  1122. X         #endif
  1123. X         return (double) 0.0;
  1124. X      }
  1125. X
  1126. X   }
  1127. X
  1128. X/***************************************************************
  1129. X
  1130. X        FUNCTION:   exp_getfval()
  1131. X
  1132. X        DESCRIPTION:
  1133. X
  1134. X***************************************************************/
  1135. X
  1136. Xfloat
  1137. Xexp_getfval( struct exp_ese *e )
  1138. X   {
  1139. X
  1140. X   #if INTENSIVE_DEBUG
  1141. X   sprintf( bwb_ebuf, "in exp_getfval(): entry" );
  1142. X   bwb_debug( bwb_ebuf );
  1143. X   #endif
  1144. X
  1145. X   /* check for variable */
  1146. X
  1147. X   if ( e->operation == VARIABLE )
  1148. X      {
  1149. X      #if INTENSIVE_DEBUG
  1150. X      sprintf( bwb_ebuf, "in exp_getfval(): returning variable" );
  1151. X      bwb_debug( bwb_ebuf );
  1152. X      #endif
  1153. X
  1154. X      switch( e->type )
  1155. X         {
  1156. X         case DOUBLE:
  1157. X            return (float) (* var_finddval( e->xvar, e->array_pos ));
  1158. X         case SINGLE:
  1159. X            return (* var_findfval( e->xvar, e->array_pos ));
  1160. X         case INTEGER:
  1161. X            return (float) (* var_findival( e->xvar, e->array_pos ));
  1162. X         default:
  1163. X            bwb_error( err_mismatch );
  1164. X            return (float) 0.0;
  1165. X         }
  1166. X      }
  1167. X
  1168. X   /* must be a numerical value */
  1169. X
  1170. X   if ( e->operation != NUMBER )
  1171. X      {
  1172. X      #if PROG_ERRORS
  1173. X      sprintf( bwb_ebuf, "in exp_getfval(): operation <%d> is not a number",
  1174. X         e->operation );
  1175. X      bwb_error( bwb_ebuf );
  1176. X      #else
  1177. X      bwb_error( err_syntax );
  1178. X      #endif
  1179. X      return (float) 0.0;
  1180. X      }
  1181. X
  1182. X   /* return specific values */
  1183. X
  1184. X   switch( e->type )
  1185. X      {
  1186. X      case SINGLE:
  1187. X         #if INTENSIVE_DEBUG
  1188. X         sprintf( bwb_ebuf, "in exp_getfval(): returning from SINGLE, val <%f>",
  1189. X            e->fval );
  1190. X         bwb_debug( bwb_ebuf );
  1191. X         #endif
  1192. X         return e->fval;
  1193. X      case INTEGER:
  1194. X         #if INTENSIVE_DEBUG
  1195. X         sprintf( bwb_ebuf, "in exp_getfval(): returning from INTEGER, val <%d>",
  1196. X            e->ival );
  1197. X         bwb_debug( bwb_ebuf );
  1198. X         #endif
  1199. X         return (float) e->ival;
  1200. X      case DOUBLE:
  1201. X         #if INTENSIVE_DEBUG
  1202. X         sprintf( bwb_ebuf, "in exp_getfval(): returning from DOUBLE, val <%lf>",
  1203. X            e->dval );
  1204. X         bwb_debug( bwb_ebuf );
  1205. X         #endif
  1206. X         return (float) e->dval;
  1207. X      default:
  1208. X         #if PROG_ERRORS
  1209. X         sprintf( bwb_ebuf, "in exp_getfval(): type is <%c>",
  1210. X            e->type );
  1211. X         bwb_error( bwb_ebuf );
  1212. X         #else
  1213. X         bwb_error( err_syntax );
  1214. X         #endif
  1215. X         return (float) 0.0;
  1216. X      }
  1217. X
  1218. X   }
  1219. X
  1220. X/***************************************************************
  1221. X
  1222. X        FUNCTION:   exp_getival()
  1223. X
  1224. X        DESCRIPTION:
  1225. X
  1226. X***************************************************************/
  1227. X
  1228. Xint
  1229. Xexp_getival( struct exp_ese *e )
  1230. X   {
  1231. X
  1232. X   /* check for variable */
  1233. X
  1234. X   if ( e->operation == VARIABLE )
  1235. X      {
  1236. X      switch( e->type )
  1237. X         {
  1238. X         case DOUBLE:
  1239. X            return (int) (* var_finddval( e->xvar, e->array_pos ));
  1240. X         case SINGLE:
  1241. X            return (int) (* var_findfval( e->xvar, e->array_pos ));
  1242. X         case INTEGER:
  1243. X            return (* var_findival( e->xvar, e->array_pos ));
  1244. X         default:
  1245. X            bwb_error( err_mismatch );
  1246. X            return 0;
  1247. X         }
  1248. X      }
  1249. X
  1250. X   /* must be a numerical value */
  1251. X
  1252. X   if ( e->operation != NUMBER )
  1253. X      {
  1254. X      #if PROG_ERRORS
  1255. X      sprintf( bwb_ebuf, "in exp_getival(): operation <%d> is not a number",
  1256. X         e->operation );
  1257. X      bwb_error( bwb_ebuf );
  1258. X      #else
  1259. X      bwb_error( err_syntax );
  1260. X      #endif
  1261. X      return 0;
  1262. X      }
  1263. X
  1264. X   /* return specific values */
  1265. X
  1266. X   switch( e->type )
  1267. X      {
  1268. X      case SINGLE:
  1269. X         return (int) e->fval;
  1270. X      case INTEGER:
  1271. X         return e->ival;
  1272. X      case DOUBLE:
  1273. X         return (int) e->dval;
  1274. X      default:
  1275. X         #if PROG_ERRORS
  1276. X         sprintf( bwb_ebuf, "in exp_getival(): type is <%c>",
  1277. X            e->type );
  1278. X         bwb_error( bwb_ebuf );
  1279. X         #else
  1280. X         bwb_error( err_syntax );
  1281. X         #endif
  1282. X         return 0;
  1283. X      }
  1284. X
  1285. X   }
  1286. X
  1287. X/***************************************************************
  1288. X
  1289. X        FUNCTION:   exp_getsval()
  1290. X
  1291. X        DESCRIPTION:
  1292. X
  1293. X***************************************************************/
  1294. X
  1295. Xbstring *
  1296. Xexp_getsval( struct exp_ese *e )
  1297. X   {
  1298. X   static bstring b;
  1299. X   #if TEST_BSTRING
  1300. X   static int init = FALSE;
  1301. X
  1302. X   if ( init == FALSE )
  1303. X      {
  1304. X      sprintf( b.name, "<exp_getsval() bstring>" );
  1305. X      }
  1306. X   #endif
  1307. X
  1308. X   b.rab = FALSE;
  1309. X
  1310. X   /* return based on operation type */
  1311. X
  1312. X   switch( e->operation )
  1313. X      {
  1314. X      case CONST_STRING:
  1315. X      case OP_STRJOIN:
  1316. X         return &( e->sval );
  1317. X      case VARIABLE:
  1318. X        switch( e->type )
  1319. X            {
  1320. X        case STRING:
  1321. X               return var_findsval( e->xvar, e->array_pos );
  1322. X            case DOUBLE:
  1323. X               sprintf( bwb_ebuf, "%lf ", exp_getdval( e ) );
  1324. X               str_ctob( &b, bwb_ebuf );
  1325. X               return &b;
  1326. X            case SINGLE:
  1327. X               sprintf( bwb_ebuf, "%f ", exp_getfval( e ) );
  1328. X               str_ctob( &b, bwb_ebuf );
  1329. X               return &b;
  1330. X            case INTEGER:
  1331. X               sprintf( bwb_ebuf, "%d ", exp_getival( e ) );
  1332. X               str_ctob( &b, bwb_ebuf );
  1333. X               return &b;
  1334. X            default:
  1335. X               #if PROG_ERRORS
  1336. X               sprintf( bwb_ebuf, "in exp_getsval(): type <%c> inappropriate for NUMBER",
  1337. X                  e->type );
  1338. X               bwb_error( bwb_ebuf );
  1339. X               #else
  1340. X               bwb_error( err_syntax );
  1341. X               #endif
  1342. X               return NULL;
  1343. X            }
  1344. X     break;
  1345. X
  1346. X      case NUMBER:
  1347. X        switch( e->type )
  1348. X            {
  1349. X        case DOUBLE:
  1350. X               sprintf( bwb_ebuf, "%lf ", exp_getdval( e ) );
  1351. X               str_ctob( &b, bwb_ebuf );
  1352. X               return &b;
  1353. X            case SINGLE:
  1354. X               sprintf( bwb_ebuf, "%f ", exp_getfval( e ) );
  1355. X               str_ctob( &b, bwb_ebuf );
  1356. X               return &b;
  1357. X            case INTEGER:
  1358. X               sprintf( bwb_ebuf, "%d ", exp_getival( e ) );
  1359. X               str_ctob( &b, bwb_ebuf );
  1360. X               return &b;
  1361. X            default:
  1362. X               #if PROG_ERRORS
  1363. X               sprintf( bwb_ebuf, "in exp_getsval(): type <%c> inappropriate for NUMBER",
  1364. X                  e->type );
  1365. X               bwb_error( bwb_ebuf );
  1366. X               #else
  1367. X               bwb_error( err_syntax );
  1368. X               #endif
  1369. X               return NULL;
  1370. X            }
  1371. X     break;
  1372. X      default:
  1373. X         #if PROG_ERRORS
  1374. X         sprintf( bwb_ebuf, "in exp_getsval(): operation <%d> inappropriate",
  1375. X            e->operation );
  1376. X         bwb_error( bwb_ebuf );
  1377. X         #else
  1378. X         bwb_error( err_syntax );
  1379. X         #endif
  1380. X         return NULL;
  1381. X      }
  1382. X
  1383. X   /* this point may not be reached */
  1384. X
  1385. X   return NULL;
  1386. X
  1387. X   }
  1388. X
  1389. X/***************************************************************
  1390. X
  1391. X        FUNCTION:   exp_findfval()
  1392. X
  1393. X        DESCRIPTION:
  1394. X
  1395. X***************************************************************/
  1396. X
  1397. X#ifdef NO_LONGER_IMPLEMENTED
  1398. Xfloat *
  1399. Xexp_findfval( struct exp_ese *e )
  1400. X   {
  1401. X
  1402. X   #if INTENSIVE_DEBUG
  1403. X   sprintf( bwb_ebuf, "in exp_findfval(): entry" );
  1404. X   bwb_debug( bwb_ebuf );
  1405. X   #endif
  1406. X
  1407. X   /* check for variable */
  1408. X
  1409. X   if ( e->operation == VARIABLE )
  1410. X      {
  1411. X      #if INTENSIVE_DEBUG
  1412. X      sprintf( bwb_ebuf, "in exp_getfval(): returning variable" );
  1413. X      bwb_debug( bwb_ebuf );
  1414. X      #endif
  1415. X      return var_findfval( e->xvar, e->xvar->array_pos );
  1416. X      }
  1417. X
  1418. X   /* must be a numerical value */
  1419. X
  1420. X   if ( ( e->operation != NUMBER ) && ( e->type != SINGLE ))
  1421. X      {
  1422. X      #if PROG_ERRORS
  1423. X      sprintf( bwb_ebuf, "in exp_findfval(): operation is not a single-precision number" );
  1424. X      bwb_error( bwb_ebuf );
  1425. X      #else
  1426. X      bwb_error( err_syntax );
  1427. X      #endif
  1428. X      return NULL;
  1429. X      }
  1430. X
  1431. X   /* return specific value */
  1432. X
  1433. X   return &( e->fval );
  1434. X
  1435. X   }
  1436. X
  1437. X/***************************************************************
  1438. X
  1439. X        FUNCTION:   exp_finddval()
  1440. X
  1441. X        DESCRIPTION:
  1442. X
  1443. X***************************************************************/
  1444. X
  1445. Xdouble *
  1446. Xexp_finddval( struct exp_ese *e )
  1447. X   {
  1448. X
  1449. X   #if INTENSIVE_DEBUG
  1450. X   sprintf( bwb_ebuf, "in exp_finddval(): entry" );
  1451. X   bwb_debug( bwb_ebuf );
  1452. X   #endif
  1453. X
  1454. X   /* check for variable */
  1455. X
  1456. X   if ( e->operation == VARIABLE )
  1457. X      {
  1458. X      #if INTENSIVE_DEBUG
  1459. X      sprintf( bwb_ebuf, "in exp_getdval(): returning variable" );
  1460. X      bwb_debug( bwb_ebuf );
  1461. X      #endif
  1462. X      return var_finddval( e->xvar, e->xvar->array_pos );
  1463. X      }
  1464. X
  1465. X   /* must be a numerical value */
  1466. X
  1467. X   if ( ( e->operation != NUMBER ) && ( e->type != SINGLE ))
  1468. X      {
  1469. X      #if PROG_ERRORS
  1470. X      sprintf( bwb_ebuf, "in exp_finddval(): operation is not a double-precision number" );
  1471. X      bwb_error( bwb_ebuf );
  1472. X      #else
  1473. X      bwb_error( err_syntax );
  1474. X      #endif
  1475. X      return NULL;
  1476. X      }
  1477. X
  1478. X   /* return specific value */
  1479. X
  1480. X   return &( e->dval );
  1481. X
  1482. X   }
  1483. X
  1484. X/***************************************************************
  1485. X
  1486. X        FUNCTION:   exp_findival()
  1487. X
  1488. X        DESCRIPTION:
  1489. X
  1490. X***************************************************************/
  1491. X
  1492. Xint *
  1493. Xexp_findival( struct exp_ese *e )
  1494. X   {
  1495. X
  1496. X   #if INTENSIVE_DEBUG
  1497. X   sprintf( bwb_ebuf, "in exp_findival(): entry" );
  1498. X   bwb_debug( bwb_ebuf );
  1499. X   #endif
  1500. X
  1501. X   /* check for variable */
  1502. X
  1503. X   if ( e->operation == VARIABLE )
  1504. X      {
  1505. X      #if INTENSIVE_DEBUG
  1506. X      sprintf( bwb_ebuf, "in exp_getival(): returning variable" );
  1507. X      bwb_debug( bwb_ebuf );
  1508. X      #endif
  1509. X      return var_findival( e->xvar, e->xvar->array_pos );
  1510. X      }
  1511. X
  1512. X   /* must be a numerical value */
  1513. X
  1514. X   if ( ( e->operation != NUMBER ) && ( e->type != SINGLE ))
  1515. X      {
  1516. X      #if PROG_ERRORS
  1517. X      sprintf( bwb_ebuf, "in exp_findival(): operation is not an integer number" );
  1518. X      bwb_error( bwb_ebuf );
  1519. X      #else
  1520. X      bwb_error( err_syntax );
  1521. X      #endif
  1522. X      return NULL;
  1523. X      }
  1524. X
  1525. X   /* return specific value */
  1526. X
  1527. X   return &( e->ival );
  1528. X
  1529. X   }
  1530. X#endif
  1531. X
  1532. X/***************************************************************
  1533. X
  1534. X        FUNCTION:   inc_esc()
  1535. X
  1536. X        DESCRIPTION:  This function increments the expression
  1537. X        stack counter.
  1538. X
  1539. X***************************************************************/
  1540. X
  1541. Xint
  1542. Xinc_esc( void )
  1543. X   {
  1544. X
  1545. X   #if INTENSIVE_DEBUG
  1546. X   sprintf( bwb_ebuf, "in inc_esc(): prev level <%d>",
  1547. X      exp_esc );
  1548. X   bwb_debug ( bwb_ebuf );
  1549. X   #endif
  1550. X
  1551. X   ++exp_esc;
  1552. X   if ( exp_esc >= ESTACKSIZE )
  1553. X      {
  1554. X      --exp_esc;
  1555. X      #if PROG_ERRORS
  1556. X      sprintf( bwb_ebuf, "in inc_esc(): Maximum expression stack exceeded <%d>",
  1557. X         exp_esc );
  1558. X      bwb_error( bwb_ebuf );
  1559. X      #else
  1560. X      bwb_error( err_overflow );
  1561. X      #endif
  1562. X      return OP_NULL;
  1563. X      }
  1564. X
  1565. X   #if INTENSIVE_DEBUG
  1566. X   sprintf( exp_es[ exp_esc ].string, "New Expression Stack Level %d", exp_esc );
  1567. X   #endif
  1568. X
  1569. X   exp_es[ exp_esc ].type = INTEGER;
  1570. X   exp_es[ exp_esc ].operation = OP_NULL;
  1571. X   exp_es[ exp_esc ].pos_adv = 0;
  1572. X
  1573. X   return TRUE;
  1574. X   }
  1575. X
  1576. X/***************************************************************
  1577. X
  1578. X        FUNCTION:   dec_esc()
  1579. X
  1580. X        DESCRIPTION:  This function decrements the expression
  1581. X        stack counter.
  1582. X
  1583. X***************************************************************/
  1584. X
  1585. Xint
  1586. Xdec_esc( void )
  1587. X   {
  1588. X   --exp_esc;
  1589. X   if ( exp_esc < 0 )
  1590. X      {
  1591. X      exp_esc = 0;
  1592. X      #if PROG_ERRORS
  1593. X      sprintf( bwb_ebuf, "in dec_esc(): Expression stack counter < 0." );
  1594. X      bwb_error( bwb_ebuf );
  1595. X      #else
  1596. X      bwb_error( err_overflow );
  1597. X      #endif
  1598. X      return OP_NULL;
  1599. X      }
  1600. X
  1601. X   return TRUE;
  1602. X   }
  1603. END_OF_FILE
  1604.   if test 40302 -ne `wc -c <'bwb_exp.c'`; then
  1605.     echo shar: \"'bwb_exp.c'\" unpacked with wrong size!
  1606.   fi
  1607.   # end of 'bwb_exp.c'
  1608. fi
  1609. if test -f 'bwbasic.doc' -a "${1}" != "-c" ; then 
  1610.   echo shar: Will not clobber existing file \"'bwbasic.doc'\"
  1611. else
  1612.   echo shar: Extracting \"'bwbasic.doc'\" \(16562 characters\)
  1613.   sed "s/^X//" >'bwbasic.doc' <<'END_OF_FILE'
  1614. X
  1615. X
  1616. X
  1617. X
  1618. X               Bywater BASIC Interpreter/Shell, version 1.10
  1619. X               ---------------------------------------------
  1620. X
  1621. X                    Copyright (c) 1992, Ted A. Campbell
  1622. X                 for bwBASIC version 1.10, 1 November 1992
  1623. X
  1624. X
  1625. XCONTENTS:
  1626. X
  1627. X   1. DESCRIPTION
  1628. X   2. TERMS OF USE
  1629. X   3. COMMANDS AND FUNCTIONS IMPLEMENTED
  1630. X   4. SOME NOTES ON USAGE
  1631. X   5. UNIMPLEMENTED COMMANDS AND FUNCTIONS
  1632. X   6. SOME NOTES ON COMPILATION
  1633. X   7. THE STORY OF BYWATER BASIC
  1634. X   8. COMMUNICATIONS
  1635. X
  1636. X
  1637. X1. DESCRIPTION
  1638. X
  1639. X   The Bywater BASIC Interpreter (bwBASIC) implements a large
  1640. X   superset of the ANSI Standard for Minimal BASIC (X3.60-1978)
  1641. X   in ANSI C and offers shell program facilities as an extension
  1642. X   of BASIC.
  1643. X
  1644. X   The set of BASIC commands and functions implemented is fairly
  1645. X   limited (see section three below), although more commands and
  1646. X   functions are implemented than appear in the specification
  1647. X   for Minimal BASIC. There are no commands that are terminal- or
  1648. X   hardware specific. (Seriously -- CLS may work under bwBASIC
  1649. X   on your DOS-based pc, but that is because bwBASIC shells
  1650. X   out to DOS when it does not recognize CLS and executes CLS there.)
  1651. X
  1652. X   The interpreter is slow.  Whenever faced with a choice between 
  1653. X   conceptual clarity and speed, I have consistently chosen
  1654. X   the former.  The interpreter is the simplest design available,
  1655. X   and utilizes no system of intermediate code, which would speed
  1656. X   up considerably its operation.  As it is, each line is interpreted
  1657. X   afresh as the interpreter comes to it. 
  1658. X
  1659. X   bwBASIC implements one feature not available in previous BASIC
  1660. X   interpreters: a shell command can be entered interactively at the
  1661. X   bwBASIC prompt, and the interpreter will execute it under a
  1662. X   command shell.  For instance, the command "dir *.bas" can be
  1663. X   entered in bwBASIC (under DOS, or "ls -l *.bas" under UNIX) and
  1664. X   it will be executed as from the operating system command line.
  1665. X   Shell commands can also be given on numbered lines in a bwBASIC
  1666. X   program, so that bwBASIC can be used as a shell programming
  1667. X   language. bwBASIC's implementation of the RMDIR, CHDIR, MKDIR,
  1668. X   NAME, KILL, ENVIRON, and ENVIRON$() commands and functions
  1669. X   offer further shell-processing capabilities.
  1670. X
  1671. X
  1672. X2. TERMS OF USE:
  1673. X
  1674. X   The bwBASIC source code and executables produced from it can be
  1675. X   used subject to the following statement which is included in
  1676. X   the header to all the source code files:
  1677. X
  1678. X        All U.S. and international copyrights are claimed by the
  1679. X        author. The author grants permission to use this code
  1680. X        and software based on it under the following conditions:
  1681. X        (a) in general, the code and software based upon it may be
  1682. X        used by individuals and by non-profit organizations; (b) it
  1683. X        may also be utilized by governmental agencies in any country,
  1684. X        with the exception of military agencies; (c) the code and/or
  1685. X        software based upon it may not be sold for a profit without
  1686. X        an explicit and specific permission from the author, except
  1687. X        that a minimal fee may be charged for media on which it is
  1688. X        copied, and for copying and handling; (d) the code must be
  1689. X        distributed in the form in which it has been released by the
  1690. X        author; and (e) the code and software based upon it may not
  1691. X        be used for illegal activities.
  1692. X
  1693. X
  1694. X3. BASIC COMMANDS AND FUNCTIONS IMPLEMENTED:
  1695. X
  1696. X   ABS( number )
  1697. X   ASC( string$ )
  1698. X   ATN( number )
  1699. X   CHAIN [MERGE] file-name [, line-number] [, ALL]
  1700. X   CHR$( number )
  1701. X   CINT( number )
  1702. X   CLEAR
  1703. X   CLOSE [[#]file-number]...
  1704. X   COMMON variable [, variable...]
  1705. X   COS( number )
  1706. X   CSNG( number )
  1707. X   CVD( string$ )
  1708. X   CVI( string$ )
  1709. X   CVS( string$ )
  1710. X   DATA constant[,constant]...
  1711. X   DATE$
  1712. X   DEF FNname(arg...)] = expression
  1713. X   DEFDBL letter[-letter](, letter[-letter])...
  1714. X   DEFINT letter[-letter](, letter[-letter])...
  1715. X   DEFSNG letter[-letter](, letter[-letter])...
  1716. X   DEFSTR letter[-letter](, letter[-letter])...
  1717. X   DELETE line[-line]
  1718. X   DIM variable(elements...)[variable(elements...)]...
  1719. X   END
  1720. X   ENVIRON variable-string = string
  1721. X   ENVIRON$( variable-string )
  1722. X   EOF( device-number )
  1723. X   ERASE variable[, variable]...
  1724. X   ERL
  1725. X   ERR
  1726. X   ERROR number
  1727. X   EXP( number )
  1728. X   FIELD [#] device-number, number AS string-variable [, number AS string-variable...]
  1729. X   FOR counter = start TO finish [STEP increment]
  1730. X   GET [#] device-number [, record-number]
  1731. X   GOSUB line
  1732. X   GOTO line
  1733. X   HEX$( number )
  1734. X   IF expression THEN statement [ELSE statement]
  1735. X   INPUT [# device-number]|[;]["prompt string";]list of variables
  1736. X   INSTR( [start-position,] string-searched$, string-pattern$ )
  1737. X   INT( number )
  1738. X   KILL file-name
  1739. X   LEFT$( string$, number-of-spaces )
  1740. X   LEN( string$ )
  1741. X   LET variable = expression
  1742. X   LINE INPUT [[#] device-number,]["prompt string";] string-variable$
  1743. X   LIST line[-line]
  1744. X   LOAD file-name
  1745. X   LOC( device-number )
  1746. X   LOF( device-number )
  1747. X   LOG( number )
  1748. X   LSET string-variable$ = expression
  1749. X   MERGE file-name
  1750. X   MID$( string$, start-position-in-string[, number-of-spaces ] )
  1751. X   MKD$( double-value# )
  1752. X   MKI$( integer-value% )
  1753. X   MKS$( single-value! )
  1754. X   NAME old-file-name AS new-file-name
  1755. X   NEW
  1756. X   NEXT counter
  1757. X   OCT$( number )
  1758. X   ON variable GOTO|GOSUB line[,line,line,...]
  1759. X   ON ERROR GOSUB line
  1760. X   OPEN O|I|R, [#]device-number, file-name [,record length]
  1761. X        file-name FOR INPUT|OUTPUT|APPEND AS [#]device-number [LEN = record-length]
  1762. X   OPTION BASE number
  1763. X   POS
  1764. X   PRINT [# device-number,][USING format-string$;] expressions...
  1765. X   PUT [#] device-number [, record-number]
  1766. X   RANDOMIZE number
  1767. X   READ variable[, variable]...
  1768. X   REM string
  1769. X   RESTORE line
  1770. X   RETURN
  1771. X   RIGHT$( string$, number-of-spaces )
  1772. X   RND( number )
  1773. X   RSET string-variable$ = expression
  1774. X   RUN [line][file-name]
  1775. X   SAVE file-name
  1776. X   SGN( number )
  1777. X   SIN( number )
  1778. X   SPACE$( number )
  1779. X   SPC( number )
  1780. X   SQR( number )
  1781. X   STOP
  1782. X   STR$( number )
  1783. X   STRING$( number, ascii-value|string$ )
  1784. X   SWAP variable, variable
  1785. X   SYSTEM
  1786. X   TAB( number )
  1787. X   TAN( number )
  1788. X   TIME$
  1789. X   TIMER
  1790. X   TROFF
  1791. X   TRON
  1792. X   VAL( string$ )
  1793. X   WEND
  1794. X   WHILE expression
  1795. X   WIDTH [# device-number,] number
  1796. X   WRITE [# device-number,] element [, element ].... 
  1797. X
  1798. X   If DIRECTORY_CMDS is set to TRUE when the program is compiled,
  1799. X   then the following commands will be available:
  1800. X
  1801. X   CHDIR pathname
  1802. X   MKDIR pathname
  1803. X   RMDIR pathname
  1804. X
  1805. X   If DEBUG is set to TRUE when the program is compiled then
  1806. X   the following debugging commands (unique to bwBASIC) will
  1807. X   be available:
  1808. X
  1809. X   VARS            (prints a list of all variables)
  1810. X   CMDS            (prints a list of all commands)
  1811. X   FNCS            (prints a list of all functions)
  1812. X
  1813. X   If COMMAND_SHELL is set to TRUE when the program is compiled,
  1814. X   then the user may enter a shell command at the bwBASIC prompt.
  1815. X
  1816. X
  1817. X4. SOME NOTES ON USAGE:
  1818. X
  1819. X   An interactive environment is provided, so that a line with a
  1820. X   line number can be entered at the bwBASIC prompt and it will be
  1821. X   added to the program in memory.
  1822. X
  1823. X   Line numbers are not strictly required, but are useful if the
  1824. X   interactive enviroment is used for programming.  For longer
  1825. X   program entry one might prefer to use an ASCII text editor, and
  1826. X   in this case lines can be entered without numbers. In this case,
  1827. X   however, one will not be able to alter the numberless lines
  1828. X   within the interactive environment.
  1829. X
  1830. X   Command names and function names are not case sensitive,
  1831. X   so that "Run" and "RUN" and "run" are equivalent and "abs()"
  1832. X   and "ABS()" and "Abs()" are equivalent. HOWEVER: variable
  1833. X   names ARE case sensitive in bwbASIC, so that "d$" and "D$"
  1834. X   are different variables.  This differs from some BASIC
  1835. X   implementations where variable names are not case sensitive.
  1836. X
  1837. X   A filename can be specified on the command line and will be
  1838. X   LOADed and RUN immediately, so that the command line
  1839. X
  1840. X      bwbasic prog.bas
  1841. X
  1842. X   will load and execute "prog.bas".
  1843. X
  1844. X   All programs are stored as ASCII text files.
  1845. X
  1846. X   TRUE is defined as -1 and FALSE is defined as 0 in the default
  1847. X   distribution of bwBASIC. These definitions can be changed by
  1848. X   those compiling bwBASIC (see file BWBASIC.H).
  1849. X
  1850. X   Assignment must be made to variables.  This differs from some
  1851. X   implementations of BASIC where assignment can be made to a
  1852. X   function.  Implication: "INSTR( 3, x$, y$ ) = z$" will not
  1853. X   work under bwBASIC.
  1854. X
  1855. X   Notes on the implementation of specific commands:
  1856. X
  1857. X   CVI(), CVD(), CVS(), MKI$(), MKD$(), MKS$(): These functions
  1858. X   are implemented, but are dependent on a) the sizes for integer,
  1859. X   float, and double values on particular systems, and b) how
  1860. X   particular versions of C store these numerical values. The
  1861. X   implication is that data files created using these functions
  1862. X   on a DOS-based microcomputer may not be translated correctly
  1863. X   by bwBASIC running on a Unix-based computer.  Similarly, data
  1864. X   files created by bwBASIC compiled by one version of C may not be
  1865. X   readable by bwBASIC compiled by another version of C (even under
  1866. X   the same operating system). So be careful with these.
  1867. X
  1868. X   ENVIRON:  The ENVIRON command requires BASIC strings on either
  1869. X   side of the equals sign.  Thus: 
  1870. X
  1871. X      environ "PATH" = "/usr/bin"
  1872. X
  1873. X   It might be noted that this differs from the implementation
  1874. X   of ENVIRON in some versions of BASIC, but bwBASIC's ENVIRON
  1875. X   allows BASIC variables to be used on either side of the equals
  1876. X   sign.  Note that the function ENVIRON$() is different from the
  1877. X   command, and be aware of the fact that in some operating systems
  1878. X   an environment variable set within a program will not be passed
  1879. X   to its parent shell.
  1880. X
  1881. X   ERR: Note that if PROG_ERRORS has been defined when bwBASIC is
  1882. X   compiled, the ERR variable will not be set correctly upon
  1883. X   errors.  It only works when standard error messages are used.
  1884. X
  1885. X   FOR and NEXT:  In this implementation of bwBASIC, a NEXT
  1886. X   statement must appear in the first position in a program
  1887. X   line; it cannot appear in a line segment beyond a colon.
  1888. X
  1889. X   INPUT: bwBASIC cannot support the optional feature of INPUT
  1890. X   that suppresses the carriage-return and line-feed at the end
  1891. X   of the input.  This is because ANSI C does not provide for any
  1892. X   means of input other than CR-LF-terminated strings.
  1893. X
  1894. X
  1895. X5. UNIMPLEMENTED COMMANDS AND FUNCTIONS
  1896. X
  1897. X   There are a few items not implemented that have been so long
  1898. X   a part of standard BASICs that their absence will seem surprising.
  1899. X   In each case, though, their implementation would require opera-
  1900. X   ting-system-specific functions or terminal-specific functions
  1901. X   that ANSI C cannot provide. Some specific examples:
  1902. X
  1903. X   CALL        In some versions of BASIC, CALL is used to call a
  1904. X        machine language subroutine, but machine language
  1905. X        routines are highly system-specific.  In other
  1906. X        BASICs (conforming to the more complete ANSI
  1907. X        definition of BASIC), CALL is used to call a
  1908. X        named subroutine.  Although it's possible that
  1909. X        bwBASIC could develop as a numberless BASIC
  1910. X        with named subroutine calls, these features
  1911. X        are not implemented in this earliest released
  1912. X        version.
  1913. X
  1914. X   CLOAD    See CALL above (machine language subroutines).
  1915. X
  1916. X   CONT        See RESUME below (programmer ignorance?).
  1917. X
  1918. X   DEF USR    See CALL above (machine language subroutines).
  1919. X
  1920. X   EDIT        EDIT would be especially nice, but requires some
  1921. X           specific knowledge of how particular computers
  1922. X           handle interaction between the screen and the
  1923. X           keyboard.  This knowledge isn't available within
  1924. X           the bounds of ANSI C alone ("innerhalb die Grenzen
  1925. X        der reinen Vernunft," with apologies to Immanuel
  1926. X        Kant).
  1927. X
  1928. X   FRE()    The ability to report the amount of free memory
  1929. X        remaining is system-specific due to varying patterns
  1930. X        of memory allocation and access; consequently this
  1931. X        ability is not present in ANSI C and this function
  1932. X        is not available in bwBASIC.
  1933. X
  1934. X   FILES    The FILES command requires a list of files conforming
  1935. X           to a specifier; ANSI C does not provide this. When
  1936. X           COMMAND_SHELL is defined as TRUE, users might want
  1937. X           to issue operating-system commands such as "DIR"
  1938. X           (DOS) or "ls -l" (Unix) to get a list of files.
  1939. X
  1940. X   INKEY$    This function requires a keyboard scan to indicate
  1941. X        whether a key is pending. Although this facility
  1942. X        is easily available on microcomputers (it is part
  1943. X        of the minimal CP/M Operating System), it is not
  1944. X        easily available on some more complex systems. 
  1945. X        Consequently, it's not part of the C standard and
  1946. X        bwBASIC has not implemented INKEY$.
  1947. X
  1948. X   INPUT$()    Similar to INKEY$ above, ANSI C by itself is not
  1949. X           able to read unechoed keyboard input, and can read
  1950. X           keyboard input only after a Carriage-Return has
  1951. X           been entered. 
  1952. X
  1953. X   INP        Calls to hardware ports, like machine-language
  1954. X           routines, are highly system-specific and cannot
  1955. X           be implemented in ANSI C alone.
  1956. X
  1957. X   LLIST    See LPRINT below.
  1958. X
  1959. X   LPOS        See LPRINT below.
  1960. X
  1961. X   LPRINT    and LLIST, etc., require access to a printer device,
  1962. X           and this varies from one system to another. Users
  1963. X           might try OPENing the printer device on their own
  1964. X           operating system (e.g., "/dev/lp" on Unix systems,
  1965. X           or "PRN" under DOS) and see if printing can be done
  1966. X           from bwBASIC in this way.
  1967. X
  1968. X   NULL        In this case, I am convinced that NULL is no longer
  1969. X        necessary, since very few printers now require NULLs
  1970. X        at the end of lines.
  1971. X
  1972. X   OUT        See INP above (calls to hardware ports).
  1973. X
  1974. X   PEEK()    PEEK and POKE enabled earlier BASICs to address
  1975. X           particular memory locations. Although bwBASIC
  1976. X           could possibly implement this command (POKE) and
  1977. X           this function (PEEK()), the limitation would be
  1978. X           highly limited by the different systems for
  1979. X           memory access in different systems.
  1980. X
  1981. X   POKE        see PEEK() above.
  1982. X
  1983. X   RENUM    Since unnumbered lines can be entered and
  1984. X           executed under bwBASIC, it would not be
  1985. X           possible to implement a RENUM routine.
  1986. X
  1987. X   RESUME    Is this possible under ANSI C? If so, I
  1988. X           simply have failed to figure it out yet.
  1989. X           Mea culpa (but not maxima).
  1990. X
  1991. X   USR        See CALL and DEF USR above (machine language
  1992. X           subroutines).
  1993. X
  1994. X   VARPTR    See PEEK and POKE above.
  1995. X
  1996. X   WAIT        See INP and OUT above.
  1997. X
  1998. X           
  1999. X6. SOME NOTES ON COMPILATION
  2000. X
  2001. X   bwBASIC is written in ANSI C and takes advantage of some of the
  2002. X   enhancements of ANSI C over the older K&R standard.  The program
  2003. X   expects to find standard ANSI C include files (such as <stddef.h>).
  2004. X   Because there is nothing terminal- or hardware-specific about it,
  2005. X   I should hope that it would compile correctly under any ANSI C
  2006. X   compiler, but you may have to construct your own makefile.
  2007. X
  2008. X   Two makefiles are currently provided: "makefile.qcl" will compile
  2009. X   the program utilizing the Microsoft QuickC (tm) line-oriented 
  2010. X   compiler on DOS-based p.c.'s, and "makefile.gcc" will compile 
  2011. X   the program utilizing the ANSI option of Gnu C++. I have also 
  2012. X   compiled the program utilizing Borland's Turbo C++ (tm) on DOS-
  2013. X   based machines.
  2014. X
  2015. X   No alterations to flags are necessary for varied environments,
  2016. X   but the beginning of file <bwbasic.h> allows the user to set
  2017. X   some debugging flags and to control some program defaults.
  2018. X   The file <bwb_mes.h> has a number of language-specific message
  2019. X   sets that can be controlled by setting the appropriate language
  2020. X   flag.
  2021. X
  2022. X
  2023. X7. THE STORY OF BYWATER BASIC
  2024. X
  2025. X   This program was originally begun in 1982 by my grandmother, Mrs.
  2026. X   Verda Spell of Beaumont, TX.  She was writing the program using
  2027. X   an ANSI C compiler on an Osborne I CP/M computer and although my
  2028. X   grandfather (Lockwood Spell) had bought an IBM PC with 256k of
  2029. X   RAM my grandmother would not use it, paraphrasing George Herbert
  2030. X   to the effect that "He who cannot in 64k program, cannot in 512k."
  2031. X   She had used Microsoft BASIC and although she had nothing against
  2032. X   it she said repeatedly that she didn't understand why Digital
  2033. X   Research didn't "sue the socks off of Microsoft" for version 1.0
  2034. X   of MSDOS and so I reckon that she hoped to undercut Microsoft's
  2035. X   entire market and eventually build a new software empire on
  2036. X   the North End of Beaumont. Her programming efforts were cut
  2037. X   tragically short when she was thrown from a Beaumont to Port
  2038. X   Arthur commuter train in the summer of 1986. I found the source
  2039. X   code to bwBASIC on a single-density Osborne diskette in her knitting
  2040. X   bag and eventually managed to have it all copied over to a PC
  2041. X   diskette. I have revised it slightly prior to this release. You
  2042. X   should know, though, that I myself am an historian, not a programmer.
  2043. X
  2044. X   
  2045. X8. COMMUNICATIONS:
  2046. X
  2047. X   Ted A. Campbell
  2048. X   Bywater Software
  2049. X   P.O. Box 4023
  2050. X   Duke Station
  2051. X   Durham, NC  27706
  2052. X   USA
  2053. X
  2054. X   email:  tcamp@acpub.duke.edu
  2055. END_OF_FILE
  2056.   if test 16562 -ne `wc -c <'bwbasic.doc'`; then
  2057.     echo shar: \"'bwbasic.doc'\" unpacked with wrong size!
  2058.   fi
  2059.   # end of 'bwbasic.doc'
  2060. fi
  2061. echo shar: End of archive 6 \(of 11\).
  2062. cp /dev/null ark6isdone
  2063. MISSING=""
  2064. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2065.     if test ! -f ark${I}isdone ; then
  2066.     MISSING="${MISSING} ${I}"
  2067.     fi
  2068. done
  2069. if test "${MISSING}" = "" ; then
  2070.     echo You have unpacked all 11 archives.
  2071.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2072. else
  2073.     echo You still must unpack the following archives:
  2074.     echo "        " ${MISSING}
  2075. fi
  2076. exit 0
  2077. exit 0 # Just in case...
  2078.