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.
 
 
 
 
 
 

1491 lines
36 KiB

  1. /****************************************************************
  2. bwb_exp.c Expression Parser
  3. for Bywater BASIC Interpreter
  4. Copyright (c) 1993, Ted A. Campbell
  5. Bywater Software
  6. email: tcamp@delphi.com
  7. Copyright and Permissions Information:
  8. All U.S. and international rights are claimed by the author,
  9. Ted A. Campbell.
  10. This software is released under the terms of the GNU General
  11. Public License (GPL), which is distributed with this software
  12. in the file "COPYING". The GPL specifies the terms under
  13. which users may copy and use the software in this distribution.
  14. A separate license is available for commercial distribution,
  15. for information on which you should contact the author.
  16. ****************************************************************/
  17. /*---------------------------------------------------------------*/
  18. /* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */
  19. /* 11/1995 (eidetics@cerf.net). */
  20. /*---------------------------------------------------------------*/
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include <math.h>
  24. #include "bwbasic.h"
  25. #include "bwb_mes.h"
  26. /***************************************************************
  27. FUNCTION: bwb_exp()
  28. DESCRIPTION: This is the function by which the expression
  29. parser is called.
  30. ***************************************************************/
  31. #if ANSI_C
  32. struct exp_ese *
  33. bwb_exp( char *expression, int assignment, int *position )
  34. #else
  35. struct exp_ese *
  36. bwb_exp( expression, assignment, position )
  37. char *expression;
  38. int assignment;
  39. int *position;
  40. #endif
  41. {
  42. struct exp_ese *rval; /* return value */
  43. int entry_level, main_loop, err_condition;
  44. char *e; /* pointer to current string */
  45. int r; /* return value from functions */
  46. register int c; /* quick counter */
  47. #if OLD_WAY
  48. int adv_loop;
  49. #endif
  50. #if INTENSIVE_DEBUG
  51. sprintf( bwb_ebuf, "entered bwb_exp(): expression <%s> assignment <%d> level <%d>",
  52. & ( expression[ *position ] ), assignment, CURTASK expsc );
  53. bwb_debug( bwb_ebuf );
  54. #endif
  55. /* save the entry level of the expression stack in order to
  56. check it at the end of this function */
  57. entry_level = CURTASK expsc;
  58. err_condition = FALSE;
  59. /* advance past whitespace or beginning of line segment */
  60. #if MULTISEG_LINES
  61. if ( expression[ *position ] == ':' )
  62. {
  63. ++( *position );
  64. }
  65. #endif
  66. adv_ws( expression, position );
  67. #if MULTISEG_LINES
  68. if ( expression[ *position ] == ':' )
  69. {
  70. ++( *position );
  71. adv_ws( expression, position );
  72. }
  73. #endif
  74. /* increment the expression stack counter to get a new level */
  75. inc_esc();
  76. /* check to be sure there is a legitimate expression
  77. and set initial parameters for the main loop */
  78. if ( is_eol( expression, position ) == TRUE )
  79. {
  80. main_loop = FALSE; /* break out of loop */
  81. }
  82. else
  83. {
  84. main_loop = TRUE;
  85. CURTASK exps[ CURTASK expsc ].pos_adv = 0;
  86. }
  87. #if OLDWAY
  88. adv_loop = TRUE;
  89. while( adv_loop == TRUE )
  90. {
  91. switch( expression[ *position ] )
  92. {
  93. case ' ': /* whitespace */
  94. case '\t':
  95. ++(*position);
  96. break;
  97. case '\0': /* end of string */
  98. case '\r':
  99. case '\n':
  100. main_loop = adv_loop = FALSE; /* break out of loop */
  101. break;
  102. default:
  103. adv_loop = FALSE;
  104. main_loop = TRUE;
  105. CURTASK exps[ CURTASK expsc ].pos_adv = 0;
  106. break;
  107. }
  108. }
  109. #endif
  110. /* main parsing loop */
  111. while ( main_loop == TRUE )
  112. {
  113. /* set variable <e> to the start of the expression */
  114. e = &( expression[ *position ] );
  115. #if INTENSIVE_DEBUG
  116. sprintf( bwb_ebuf, "in bwb_exp(): main loop, level <%d> element <%s> ",
  117. CURTASK expsc, e );
  118. bwb_debug( bwb_ebuf );
  119. #endif
  120. /* detect the operation required at this level */
  121. CURTASK exps[ CURTASK expsc ].operation = exp_findop( e );
  122. #if INTENSIVE_DEBUG
  123. sprintf( bwb_ebuf, "in bwb_exp(): exp_findop() returned <%d>",
  124. CURTASK exps[ CURTASK expsc ].operation );
  125. bwb_debug( bwb_ebuf );
  126. #endif
  127. /* perform actions specific to the operation */
  128. switch( CURTASK exps[ CURTASK expsc ].operation )
  129. {
  130. case OP_ERROR:
  131. main_loop = FALSE;
  132. err_condition = TRUE;
  133. break;
  134. case OP_TERMINATE: /* terminate at THEN, ELSE, TO */
  135. #if INTENSIVE_DEBUG
  136. bwb_debug( "in bwb_exp(): Found OP_TERMINATE" );
  137. #endif
  138. case OP_STRJOIN: /* string join or tab */
  139. case OP_STRTAB:
  140. main_loop = FALSE;
  141. err_condition = FALSE;
  142. dec_esc();
  143. break;
  144. case OP_ADD: /* in the case of any numerical operation, */
  145. case OP_SUBTRACT:
  146. case OP_MULTIPLY:
  147. case OP_DIVIDE:
  148. case OP_MODULUS:
  149. case OP_EXPONENT:
  150. case OP_INTDIVISION:
  151. case OP_GREATERTHAN:
  152. case OP_LESSTHAN:
  153. case OP_GTEQ:
  154. case OP_LTEQ:
  155. case OP_NOTEQUAL:
  156. case OP_NOT:
  157. case OP_AND:
  158. case OP_OR:
  159. case OP_XOR:
  160. case OP_IMPLIES:
  161. case OP_EQUIV:
  162. case OP_NEGATION: /* JBV */
  163. #if INTENSIVE_DEBUG
  164. sprintf( bwb_ebuf, "in bwb_exp(): operator detected." );
  165. bwb_debug( bwb_ebuf );
  166. #endif
  167. CURTASK exps[ CURTASK expsc ].pos_adv = -1; /* set to strange number */
  168. /* cycle through operator table to find match */
  169. for ( c = 0; c < N_OPERATORS; ++c )
  170. {
  171. if ( exp_ops[ c ].operation == CURTASK exps[ CURTASK expsc ].operation )
  172. {
  173. CURTASK exps[ CURTASK expsc ].pos_adv = strlen( exp_ops[ c ].symbol );
  174. }
  175. }
  176. if ( CURTASK exps[ CURTASK expsc ].pos_adv == -1 ) /* was a match found? */
  177. {
  178. CURTASK exps[ CURTASK expsc ].pos_adv = 0; /* no -- set to 0 */
  179. }
  180. break; /* and move on */
  181. case OP_EQUALS:
  182. #if INTENSIVE_DEBUG
  183. sprintf( bwb_ebuf, "in bwb_exp(): equal sign detected." );
  184. bwb_debug( bwb_ebuf );
  185. #endif
  186. if ( assignment == TRUE )
  187. {
  188. CURTASK exps[ CURTASK expsc ].operation = OP_ASSIGN;
  189. }
  190. CURTASK exps[ CURTASK expsc ].pos_adv = 1;
  191. break;
  192. case PARENTHESIS:
  193. r = exp_paren( e );
  194. break;
  195. case CONST_STRING:
  196. r = exp_strconst( e );
  197. break;
  198. case CONST_NUMERICAL:
  199. r = exp_numconst( e );
  200. #if INTENSIVE_DEBUG
  201. sprintf( bwb_ebuf, "in bwb_exp(): return from exp_numconst(), r = <%d>",
  202. r );
  203. bwb_debug( bwb_ebuf );
  204. #endif
  205. break;
  206. case FUNCTION:
  207. #if INTENSIVE_DEBUG
  208. sprintf( bwb_ebuf, "in bwb_exp(): calling exp_function(), expression <%s>",
  209. e );
  210. bwb_debug( bwb_ebuf );
  211. #endif
  212. r = exp_function( e );
  213. break;
  214. case OP_USERFNC:
  215. #if INTENSIVE_DEBUG
  216. sprintf( bwb_ebuf, "in bwb_exp(): calling exp_ufnc(), expression <%s>",
  217. e );
  218. bwb_debug( bwb_ebuf );
  219. #endif
  220. r = exp_ufnc( e );
  221. #if INTENSIVE_DEBUG
  222. sprintf( bwb_ebuf, "in bwb_exp(): return from exp_ufnc(), buffer <%s>",
  223. &( expression[ *position ] ) );
  224. bwb_debug( bwb_ebuf );
  225. #endif
  226. break;
  227. case VARIABLE:
  228. r = exp_variable( e );
  229. break;
  230. default:
  231. err_condition = TRUE;
  232. main_loop = FALSE;
  233. #if PROG_ERRORS
  234. sprintf( bwb_ebuf, "in bwb_exp.c:bwb_exp(): unidentified operation (%d).",
  235. CURTASK exps[ CURTASK expsc ].operation );
  236. bwb_error( bwb_ebuf );
  237. #else
  238. bwb_error( err_syntax );
  239. #endif
  240. break;
  241. }
  242. /* increment *position counter based on previous actions */
  243. *position += CURTASK exps[ CURTASK expsc ].pos_adv;
  244. CURTASK exps[ CURTASK expsc ].pos_adv = 0; /* reset advance counter */
  245. #if INTENSIVE_DEBUG
  246. sprintf( bwb_ebuf, "in bwb_exp(): advanced position; r <%d> err_c <%d>",
  247. r, err_condition );
  248. bwb_debug( bwb_ebuf );
  249. #endif
  250. #if INTENSIVE_DEBUG
  251. if ( CURTASK exps[ CURTASK expsc ].operation == OP_EQUALS )
  252. {
  253. sprintf( bwb_ebuf, "in bwb_exp(): with OP_EQUALS: finished case" );
  254. bwb_debug( bwb_ebuf );
  255. }
  256. #endif
  257. /* check for end of string */
  258. if ( is_eol( expression, position ) == TRUE )
  259. {
  260. main_loop = FALSE; /* break out of loop */
  261. }
  262. #if OLDWAY
  263. adv_loop = TRUE;
  264. while( adv_loop == TRUE )
  265. {
  266. switch( expression[ *position ] )
  267. {
  268. case ' ': /* whitespace */
  269. case '\t':
  270. ++(*position);
  271. break;
  272. case '\0': /* end of string */
  273. case '\r':
  274. case '\n':
  275. case ':':
  276. main_loop = adv_loop = FALSE; /* break out of loop */
  277. break;
  278. default:
  279. adv_loop = FALSE;
  280. break;
  281. }
  282. }
  283. #endif
  284. /* get a new stack level before looping */
  285. if ( main_loop == TRUE )
  286. {
  287. r = inc_esc();
  288. #if INTENSIVE_DEBUG
  289. sprintf( bwb_ebuf, "in bwb_exp(): increment esc, r <%d>, err_c <%d>",
  290. r, err_condition );
  291. bwb_debug( bwb_ebuf );
  292. #endif
  293. }
  294. /* check for error return */
  295. if ( r == OP_ERROR )
  296. {
  297. #if INTENSIVE_DEBUG
  298. sprintf( bwb_ebuf, "in bwb_exp(): found r == OP_ERROR." );
  299. bwb_debug( bwb_ebuf );
  300. #endif
  301. main_loop = FALSE;
  302. err_condition = TRUE;
  303. }
  304. else
  305. {
  306. r = TRUE;
  307. }
  308. } /* end of main parsing loop */
  309. #if INTENSIVE_DEBUG
  310. sprintf( bwb_ebuf, "in bwb_exp(): breakout from main parsing loop, r <%d> err_c <%d>",
  311. r, err_condition );
  312. bwb_debug( bwb_ebuf );
  313. #endif
  314. /* check error condition */
  315. if ( err_condition == TRUE )
  316. {
  317. #if INTENSIVE_DEBUG
  318. sprintf( bwb_ebuf, "error detected in expression parser" );
  319. bwb_debug( bwb_ebuf );
  320. #endif
  321. /* decrement the expression stack counter until it matches entry_level */
  322. while( CURTASK expsc > entry_level )
  323. {
  324. dec_esc();
  325. }
  326. #if PROG_ERRORS
  327. bwb_error( "in bwb_exp(): Error detected in parsing expression" );
  328. #else
  329. bwb_error( err_syntax );
  330. #endif
  331. }
  332. /* no error; normal exit from function */
  333. else
  334. {
  335. /* are any more operations needed? if we are still at entry level,
  336. then they are not */
  337. /* try operations */
  338. exp_operation( entry_level );
  339. /* see what is on top of the stack */
  340. if ( CURTASK expsc > ( entry_level + 1 ))
  341. {
  342. switch( CURTASK exps[ CURTASK expsc ].operation )
  343. {
  344. case OP_STRJOIN:
  345. if ( CURTASK expsc != ( entry_level + 2 ))
  346. {
  347. #if PROG_ERRORS
  348. sprintf( bwb_ebuf, "in bwb_exp(): OP_STRJOIN in wrong position." );
  349. bwb_error( bwb_ebuf );
  350. #else
  351. bwb_error( err_syntax );
  352. #endif
  353. }
  354. break;
  355. default:
  356. #if PROG_ERRORS
  357. sprintf( bwb_ebuf, "in bwb_exp(): incomplete expression." );
  358. bwb_error( bwb_ebuf );
  359. #else
  360. bwb_error( err_syntax );
  361. #endif
  362. break;
  363. }
  364. /* decrement the expression stack counter */
  365. #if INTENSIVE_DEBUG
  366. sprintf( bwb_ebuf, "in bwb_exp(): before dec_esc type is <%c>",
  367. CURTASK exps[ CURTASK expsc ].type );
  368. bwb_debug( bwb_ebuf );
  369. #endif
  370. dec_esc();
  371. }
  372. /* assign rvar to the variable for the current level */
  373. rval = &( CURTASK exps[ CURTASK expsc ] );
  374. /* decrement the expression stack counter */
  375. dec_esc();
  376. /* check the current level before exit */
  377. if ( entry_level != CURTASK expsc )
  378. {
  379. #if PROG_ERRORS
  380. sprintf( bwb_ebuf, "in bwb_exp(): exit stack level (%d) does not match entry stack level (%d)",
  381. CURTASK expsc, entry_level );
  382. bwb_error( bwb_ebuf );
  383. #else
  384. bwb_error( err_overflow );
  385. #endif
  386. }
  387. }
  388. /* return a pointer to the last stack level */
  389. return rval;
  390. }
  391. /***************************************************************
  392. FUNCTION: exp_findop()
  393. DESCRIPTION: This function reads the expression to find
  394. what operation is required at its stack level.
  395. ***************************************************************/
  396. #if ANSI_C
  397. int
  398. exp_findop( char *expression )
  399. #else
  400. int
  401. exp_findop( expression )
  402. char *expression;
  403. #endif
  404. {
  405. register int c; /* character counter */
  406. int carry_on; /* boolean: control while loop */
  407. int rval; /* return value */
  408. char cbuf[ MAXSTRINGSIZE + 1 ]; /* capitalized expression */
  409. char nbuf[ MAXSTRINGSIZE + 1 ]; /* non-capitalized expression */
  410. int position; /* position in the expression */
  411. int adv_loop; /* control loop to build expression */
  412. #if INTENSIVE_DEBUG
  413. sprintf( bwb_ebuf, "in exp_findop(): received <%s>", expression );
  414. bwb_debug( bwb_ebuf );
  415. #endif
  416. /* set return value to OP_NULL initially */
  417. rval = OP_NULL;
  418. /* assign local pointer to expression to begin reading */
  419. position = 0;
  420. /* advance to the first significant character */
  421. adv_ws( expression, &position );
  422. #if INTENSIVE_DEBUG
  423. sprintf( bwb_ebuf, "in exp_findop(): expression after advance <%s>",
  424. &( expression[ position ] ) );
  425. bwb_debug( bwb_ebuf );
  426. #endif
  427. /* we now have the first significant character and can begin parsing */
  428. /* check the first character for an indication of a parenthetical
  429. expression, a string constant, or a numerical constant that begins
  430. with a digit (numerical constants beginning with a plus or minus
  431. sign or hex/octal/binary constants will have to be detected by
  432. exp_isnc() */
  433. carry_on = TRUE;
  434. switch ( expression[ position ] )
  435. {
  436. case '\"': /* this should indicate a string constant */
  437. rval = CONST_STRING;
  438. break;
  439. case '(': /* this will indicate a simple parenthetical expression */
  440. rval = PARENTHESIS;
  441. break;
  442. #if MULTISEG_LINES
  443. case ':': /* terminate processing */
  444. #endif
  445. case ')': /* end of argument list? */
  446. rval = OP_TERMINATE;
  447. break;
  448. case '0': /* these will indicate a numerical constant */
  449. case '1':
  450. case '2':
  451. case '3':
  452. case '4':
  453. case '5':
  454. case '6':
  455. case '7':
  456. case '8':
  457. case '9':
  458. case '.':
  459. case '&': /* designator for hex or octal constant */
  460. rval = CONST_NUMERICAL;
  461. break;
  462. }
  463. #if INTENSIVE_DEBUG
  464. sprintf( bwb_ebuf, "in exp_findop(): rval pos 1 is <%d>", rval );
  465. bwb_debug( bwb_ebuf );
  466. #endif
  467. /* String constants, numerical constants, open parentheses, and
  468. the plus and minus operators have been checked at this point;
  469. but if the return value is still OP_NULL, other possibilities
  470. must be checked, namely, other operators, function names, and
  471. variable names. The function adv_element cannot be used here
  472. because it will stop, e.g., with certain operators and not
  473. include them in the returned element. */
  474. /* get a character string to be interpreted */
  475. adv_loop = TRUE;
  476. cbuf[ 0 ] = '\0';
  477. nbuf[ 0 ] = '\0';
  478. c = 0;
  479. while ( adv_loop == TRUE )
  480. {
  481. #if INTENSIVE_DEBUG
  482. sprintf( bwb_ebuf, "in exp_findop() loop position <%d> char 0x%x",
  483. c, expression[ position ] );
  484. bwb_debug( bwb_ebuf );
  485. #endif
  486. switch( expression[ position ] )
  487. {
  488. case ' ': /* whitespace */
  489. case '\t':
  490. case '\r': /* end of line */
  491. case '\n':
  492. case '\0': /* end of string */
  493. case '(': /* parenthesis terminating function name */
  494. adv_loop = FALSE;
  495. break;
  496. default:
  497. nbuf[ c ] = cbuf[ c ] = expression[ position ];
  498. ++c;
  499. nbuf[ c ] = cbuf[ c ] = '\0';
  500. ++position;
  501. break;
  502. }
  503. if ( c >= MAXSTRINGSIZE )
  504. {
  505. adv_loop = FALSE;
  506. }
  507. }
  508. bwb_strtoupper( cbuf );
  509. #if INTENSIVE_DEBUG
  510. sprintf( bwb_ebuf, "in exp_findop(): cbuf element is <%s>", cbuf );
  511. bwb_debug( bwb_ebuf );
  512. #endif
  513. /* check for numerical constant */
  514. if ( rval == OP_NULL )
  515. {
  516. rval = exp_isnc( cbuf );
  517. }
  518. /* check for other operators */
  519. if ( rval == OP_NULL )
  520. {
  521. rval = exp_isop( cbuf );
  522. }
  523. /* check for user-defined function */
  524. if ( rval == OP_NULL )
  525. {
  526. rval = exp_isufn( nbuf );
  527. }
  528. /* check for function name */
  529. if ( rval == OP_NULL )
  530. {
  531. rval = exp_isfn( nbuf );
  532. }
  533. /* check for a BASIC command, esp. to catch THEN or ELSE */
  534. if ( rval == OP_NULL )
  535. {
  536. rval = exp_iscmd( cbuf );
  537. }
  538. /* last: check for variable name, and assign it if there
  539. is not already one */
  540. if ( rval == OP_NULL )
  541. {
  542. rval = exp_isvn( nbuf );
  543. }
  544. /* return the value assigned (or OP_ERROR if none assigned) */
  545. if ( rval == OP_NULL )
  546. {
  547. return OP_ERROR;
  548. }
  549. else
  550. {
  551. return rval;
  552. }
  553. }
  554. /***************************************************************
  555. FUNCTION: exp_isnc()
  556. DESCRIPTION: This function reads the expression to find
  557. if a numerical constant is present at this
  558. point.
  559. ***************************************************************/
  560. #if ANSI_C
  561. int
  562. exp_isnc( char *expression )
  563. #else
  564. int
  565. exp_isnc( expression )
  566. char *expression;
  567. #endif
  568. {
  569. char tbuf[ MAXVARNAMESIZE + 1 ]; /* JBV */
  570. switch( expression[ 0 ] )
  571. {
  572. case '0': /* these will indicate a numerical constant */
  573. case '1':
  574. case '2':
  575. case '3':
  576. case '4':
  577. case '5':
  578. case '6':
  579. case '7':
  580. case '8':
  581. case '9':
  582. case '&': /* indicator for hex or octal constant */
  583. return CONST_NUMERICAL;
  584. case '+':
  585. case '-':
  586. /* if the previous stack level was a numerical value or a string,
  587. then this is certainly not one; return OP_NULL here
  588. and let the next function call to exp_isop() determine
  589. the (plus or minus) operator */
  590. if ( ( CURTASK exps[ CURTASK expsc - 1 ].operation == NUMBER )
  591. || ( CURTASK exps[ CURTASK expsc - 1 ].operation == VARIABLE )
  592. || ( CURTASK exps[ CURTASK expsc - 1 ].operation == CONST_STRING ) )
  593. {
  594. #if INTENSIVE_DEBUG
  595. sprintf( bwb_ebuf, "in exp_isnc(): previous function is a number or string" );
  596. bwb_debug( bwb_ebuf );
  597. #endif
  598. return OP_NULL;
  599. }
  600. /* similarly, if the previous stack level was a variable
  601. with a numerical value (not a string), then this level
  602. must be an operator, not a numerical constant */
  603. if ( ( CURTASK exps[ CURTASK expsc - 1 ].operation == VARIABLE )
  604. && ( CURTASK exps[ CURTASK expsc - 1 ].type != STRING ))
  605. {
  606. return OP_NULL;
  607. }
  608. /*--------------------------------------------------------*/
  609. /* Check for unary minus sign added by JBV. */
  610. /* Could be prefixing a parenthetical expression or a */
  611. /* variable name. */
  612. /* But parentheses won't show up in expression (cbuf), so */
  613. /* just check for expression and variable name lengths. */
  614. /*--------------------------------------------------------*/
  615. if (expression[0] == '-')
  616. {
  617. if (strlen(expression) == 1) return OP_NEGATION;
  618. exp_getvfname(&expression[1], tbuf);
  619. if (strlen(tbuf) != 0) return OP_NEGATION;
  620. }
  621. /* failing these tests, the argument must be a numerical
  622. constant preceded by a plus or minus sign */
  623. return CONST_NUMERICAL;
  624. default:
  625. return OP_NULL;
  626. }
  627. }
  628. /***************************************************************
  629. FUNCTION: exp_isop()
  630. DESCRIPTION: This function reads the expression to find
  631. if a logical or mathematical operation is
  632. required at this point.
  633. This function presupposes that a numerical constant with
  634. affixed plus or minus sign has been ruled out.
  635. ***************************************************************/
  636. #if ANSI_C
  637. int
  638. exp_isop( char *expression )
  639. #else
  640. int
  641. exp_isop( expression )
  642. char *expression;
  643. #endif
  644. {
  645. register int c; /* counter */
  646. #if INTENSIVE_DEBUG
  647. sprintf( bwb_ebuf, "in exp_isop(): expression is <%s>", expression );
  648. bwb_debug( bwb_ebuf );
  649. #endif
  650. /* compare the initial characters of the string with the table
  651. of operators */
  652. for ( c = 0; c < N_OPERATORS; ++c )
  653. {
  654. if ( strncmp( expression, exp_ops[ c ].symbol,
  655. (size_t) strlen( exp_ops[ c ].symbol ) ) == 0 )
  656. {
  657. #if INTENSIVE_DEBUG
  658. sprintf( bwb_ebuf, "in exp_isop(): match <%s>, number <%d>.",
  659. exp_ops[ c ].symbol, c );
  660. bwb_debug( bwb_ebuf );
  661. #endif
  662. return exp_ops[ c ].operation;
  663. }
  664. }
  665. /* search failed; return OP_NULL */
  666. return OP_NULL;
  667. }
  668. /***************************************************************
  669. FUNCTION: exp_iscmd()
  670. DESCRIPTION: This function reads the expression to find
  671. if a BASIC command name is present; if so,
  672. it returns OP_TERMINATE to terminate expression
  673. parsing. This is critical, for example, in
  674. parsing a conditional following IF where THEN,
  675. ELSE, and other BASIC commands may follow.
  676. ***************************************************************/
  677. #if ANSI_C
  678. int
  679. exp_iscmd( char *expression )
  680. #else
  681. int
  682. exp_iscmd( expression )
  683. char *expression;
  684. #endif
  685. {
  686. register int n;
  687. #if INTENSIVE_DEBUG
  688. sprintf( bwb_ebuf, "in exp_iscmd(): expression received <%s>",
  689. expression );
  690. bwb_debug( bwb_ebuf );
  691. #endif
  692. /* first check for THEN or ELSE statements */
  693. if ( strcmp( expression, CMD_THEN ) == 0 )
  694. {
  695. #if INTENSIVE_DEBUG
  696. sprintf( bwb_ebuf, "in exp_iscmd(): match found, <%s>",
  697. expression );
  698. bwb_debug( bwb_ebuf );
  699. #endif
  700. return OP_TERMINATE;
  701. }
  702. #if STRUCT_CMDS
  703. if ( strcmp( expression, CMD_TO ) == 0 )
  704. {
  705. #if INTENSIVE_DEBUG
  706. sprintf( bwb_ebuf, "in exp_iscmd(): match found, <%s>",
  707. expression );
  708. bwb_debug( bwb_ebuf );
  709. #endif
  710. return OP_TERMINATE;
  711. }
  712. #endif
  713. if ( strcmp( expression, CMD_ELSE ) == 0 )
  714. {
  715. #if INTENSIVE_DEBUG
  716. sprintf( bwb_ebuf, "in exp_iscmd(): match found, <%s>",
  717. expression );
  718. bwb_debug( bwb_ebuf );
  719. #endif
  720. return OP_TERMINATE;
  721. }
  722. /* run through the command table and search for a match */
  723. for ( n = 0; n < COMMANDS; ++n )
  724. {
  725. if ( strcmp( expression, bwb_cmdtable[ n ].name ) == 0 )
  726. {
  727. #if INTENSIVE_DEBUG
  728. sprintf( bwb_ebuf, "in exp_iscmd(): match found, <%s>",
  729. expression );
  730. bwb_debug( bwb_ebuf );
  731. #endif
  732. return OP_TERMINATE;
  733. }
  734. #if INTENSIVE_DEBUG
  735. else
  736. {
  737. sprintf( bwb_ebuf, "in exp_iscmd(): No match, <%s> and <%s>; returns %d",
  738. expression, bwb_cmdtable[ n ].name,
  739. strcmp( expression, bwb_cmdtable[ n ].name ) );
  740. bwb_debug( bwb_ebuf );
  741. }
  742. #endif
  743. }
  744. /* search failed, return NULL */
  745. return OP_NULL;
  746. }
  747. /***************************************************************
  748. FUNCTION: exp_isufn()
  749. DESCRIPTION: This function reads the expression to find
  750. if a user-defined function name is present
  751. at this point.
  752. ***************************************************************/
  753. #if ANSI_C
  754. int
  755. exp_isufn( char *expression )
  756. #else
  757. int
  758. exp_isufn( expression )
  759. char *expression;
  760. #endif
  761. {
  762. struct fslte *f;
  763. char tbuf[ MAXVARNAMESIZE + 1 ];
  764. exp_getvfname( expression, tbuf );
  765. for ( f = CURTASK fslt_start.next; f != &CURTASK fslt_end; f = f->next )
  766. {
  767. if ( strcmp( f->name, tbuf ) == 0 )
  768. {
  769. #if INTENSIVE_DEBUG
  770. sprintf( bwb_ebuf, "in exp_isufn(): found user function <%s>",
  771. tbuf );
  772. bwb_debug( bwb_ebuf );
  773. #endif
  774. /* a user function name was found: but is it the local variable
  775. name for the user function? If so, return OP_NULL and the
  776. name will be read as a variable */
  777. if ( var_islocal( tbuf ) != NULL )
  778. {
  779. return OP_NULL;
  780. }
  781. else
  782. {
  783. #if INTENSIVE_DEBUG
  784. sprintf( bwb_ebuf, "in exp_isufn(): found function <%s> not a local variable, EXEC level <%d>",
  785. tbuf, CURTASK exsc );
  786. bwb_debug( bwb_ebuf );
  787. getchar();
  788. #endif
  789. return OP_USERFNC;
  790. }
  791. }
  792. }
  793. return OP_NULL;
  794. }
  795. /***************************************************************
  796. FUNCTION: exp_isfn()
  797. DESCRIPTION: This function reads the expression to find
  798. if a function name is present at this point.
  799. ***************************************************************/
  800. #if ANSI_C
  801. int
  802. exp_isfn( char *expression )
  803. #else
  804. int
  805. exp_isfn( expression )
  806. char *expression;
  807. #endif
  808. {
  809. /* Block out the call to exp_getvfname() if exp_isvn() is called
  810. after exp_isfn() */
  811. exp_getvfname( expression, CURTASK exps[ CURTASK expsc ].string );
  812. #if INTENSIVE_DEBUG
  813. sprintf( bwb_ebuf, "in exp_isfn(): search for function <%s>",
  814. expression );
  815. bwb_debug( bwb_ebuf );
  816. #endif
  817. if ( fnc_find( CURTASK exps[ CURTASK expsc ].string ) == NULL )
  818. {
  819. #if INTENSIVE_DEBUG
  820. sprintf( bwb_ebuf, "in exp_isfn(): failed to find function <%s>",
  821. expression );
  822. bwb_debug( bwb_ebuf );
  823. #endif
  824. return OP_NULL;
  825. }
  826. else
  827. {
  828. #if INTENSIVE_DEBUG
  829. sprintf( bwb_ebuf, "in exp_isfn(): found function <%s>",
  830. expression );
  831. bwb_debug( bwb_ebuf );
  832. #endif
  833. return FUNCTION;
  834. }
  835. }
  836. /***************************************************************
  837. FUNCTION: exp_isvn()
  838. DESCRIPTION: This function reads the expression to find
  839. if a variable name at this point.
  840. ***************************************************************/
  841. #if ANSI_C
  842. int
  843. exp_isvn( char *expression )
  844. #else
  845. int
  846. exp_isvn( expression )
  847. char *expression;
  848. #endif
  849. {
  850. /* Block out the call to exp_getvfname() if exp_isfn() is called
  851. after exp_isvn() */
  852. /* exp_getvfname( expression, CURTASK exps[ CURTASK expsc ].string ); */
  853. /* rule out null name */
  854. if ( strlen( CURTASK exps[ CURTASK expsc ].string ) == 0 )
  855. {
  856. return OP_NULL;
  857. }
  858. #if INTENSIVE_DEBUG
  859. sprintf( bwb_ebuf, "in exp_isvn(): search for variable <%s>",
  860. CURTASK exps[ CURTASK expsc ].string );
  861. bwb_debug( bwb_ebuf );
  862. #endif
  863. if ( var_find( CURTASK exps[ CURTASK expsc ].string ) == NULL )
  864. {
  865. #if INTENSIVE_DEBUG
  866. sprintf( bwb_ebuf, "in exp_isvn(): failed to find variable <%s>",
  867. expression );
  868. bwb_debug( bwb_ebuf );
  869. #endif
  870. return OP_NULL;
  871. }
  872. else
  873. {
  874. #if INTENSIVE_DEBUG
  875. sprintf( bwb_ebuf, "in exp_isvn(): found variable <%s>",
  876. CURTASK exps[ CURTASK expsc ].string );
  877. bwb_debug( bwb_ebuf );
  878. #endif
  879. return VARIABLE;
  880. }
  881. }
  882. /***************************************************************
  883. FUNCTION: exp_getvfname()
  884. DESCRIPTION: This function reads the expression to find
  885. a variable or function name at this point.
  886. ***************************************************************/
  887. #if ANSI_C
  888. int
  889. exp_getvfname( char *source, char *destination )
  890. #else
  891. int
  892. exp_getvfname( source, destination )
  893. char *source;
  894. char *destination;
  895. #endif
  896. {
  897. int s_pos, d_pos; /* source, destination positions */
  898. #if INTENSIVE_DEBUG
  899. sprintf( bwb_ebuf, "in exp_getvfname(): source buffer <%s>", source );
  900. bwb_debug( bwb_ebuf );
  901. #endif
  902. s_pos = d_pos = 0;
  903. destination[ 0 ] = '\0';
  904. while( source[ s_pos ] != '\0' )
  905. {
  906. /* all alphabetical characters are acceptable */
  907. if ( isalpha( source[ s_pos ] ) != 0 )
  908. {
  909. destination[ d_pos ] = source[ s_pos ];
  910. ++d_pos;
  911. ++s_pos;
  912. destination[ d_pos ] = '\0';
  913. }
  914. /* numerical characters are acceptable but not in the first position */
  915. else if (( isdigit( source[ s_pos ] ) != 0 ) && ( d_pos != 0 ))
  916. {
  917. destination[ d_pos ] = source[ s_pos ];
  918. ++d_pos;
  919. ++s_pos;
  920. destination[ d_pos ] = '\0';
  921. }
  922. /* other characters will have to be tried on their own merits */
  923. else
  924. {
  925. switch( source[ s_pos ] )
  926. {
  927. case '.': /* tolerated non-alphabetical characters */
  928. case '_':
  929. destination[ d_pos ] = source[ s_pos ];
  930. ++d_pos;
  931. ++s_pos;
  932. destination[ d_pos ] = '\0';
  933. break;
  934. case STRING: /* terminating characters */
  935. case '#': /* Microsoft-type double precision */
  936. case '!': /* Microsoft-type single precision */
  937. destination[ d_pos ] = source[ s_pos ];
  938. ++d_pos;
  939. ++s_pos;
  940. destination[ d_pos ] = '\0';
  941. return TRUE;
  942. case '(': /* begin function/sub name */
  943. return TRUE;
  944. default: /* anything else is non-tolerated */
  945. return FALSE;
  946. }
  947. }
  948. }
  949. #if INTENSIVE_DEBUG
  950. sprintf( bwb_ebuf, "in exp_getvfname(): found name <%s>", destination );
  951. bwb_debug( bwb_ebuf );
  952. #endif
  953. return TRUE; /* exit after coming to the end */
  954. }
  955. /***************************************************************
  956. FUNCTION: exp_validarg()
  957. DESCRIPTION: This function reads the expression to
  958. determine whether it is a valid argument (to be
  959. read recursively by bwb_exp() and passed to a
  960. function.
  961. ***************************************************************/
  962. #if ANSI_C
  963. int
  964. exp_validarg( char *expression )
  965. #else
  966. int
  967. exp_validarg( expression )
  968. char *expression;
  969. #endif
  970. {
  971. register int c;
  972. #if INTENSIVE_DEBUG
  973. sprintf( bwb_ebuf, "in exp_validarg(): expression <%s>.",
  974. expression );
  975. bwb_debug( bwb_ebuf );
  976. #endif
  977. c = 0;
  978. while ( TRUE )
  979. {
  980. switch( expression[ c ] )
  981. {
  982. case ' ':
  983. case '\t':
  984. ++c;
  985. break;
  986. case '\0':
  987. return FALSE;
  988. default:
  989. return TRUE;
  990. }
  991. }
  992. }
  993. /***************************************************************
  994. FUNCTION: exp_getnval()
  995. DESCRIPTION: This function returns the numerical value
  996. contain in the expression-stack element
  997. pointed to by 'e'.
  998. ***************************************************************/
  999. #if ANSI_C
  1000. bnumber
  1001. exp_getnval( struct exp_ese *e )
  1002. #else
  1003. bnumber
  1004. exp_getnval( e )
  1005. struct exp_ese *e;
  1006. #endif
  1007. {
  1008. /* check for variable */
  1009. if ( e->operation == VARIABLE )
  1010. {
  1011. switch( e->type )
  1012. {
  1013. case NUMBER:
  1014. return (* var_findnval( e->xvar, e->array_pos ));
  1015. default:
  1016. bwb_error( err_mismatch );
  1017. return (bnumber) 0.0;
  1018. }
  1019. }
  1020. /* must be a numerical value */
  1021. if ( e->operation != NUMBER )
  1022. {
  1023. #if PROG_ERRORS
  1024. sprintf( bwb_ebuf, "in exp_getnval(): operation <%d> is not a number",
  1025. e->operation );
  1026. bwb_error( bwb_ebuf );
  1027. #else
  1028. bwb_error( err_syntax );
  1029. #endif
  1030. return (bnumber) 0.0;
  1031. }
  1032. /* return specific values */
  1033. switch( e->type )
  1034. {
  1035. case NUMBER:
  1036. return e->nval;
  1037. default:
  1038. #if PROG_ERRORS
  1039. sprintf( bwb_ebuf, "in exp_getnval(): type is <%c>",
  1040. e->type );
  1041. bwb_error( bwb_ebuf );
  1042. #else
  1043. bwb_error( err_syntax );
  1044. #endif
  1045. return (bnumber) 0.0;
  1046. }
  1047. }
  1048. /***************************************************************
  1049. FUNCTION: exp_getsval()
  1050. DESCRIPTION: This function returns a pointer to the
  1051. BASIC string structure pointed to by
  1052. expression-stack element 'e'.
  1053. ***************************************************************/
  1054. #if ANSI_C
  1055. bstring *
  1056. exp_getsval( struct exp_ese *e )
  1057. #else
  1058. bstring *
  1059. exp_getsval( e )
  1060. struct exp_ese *e;
  1061. #endif
  1062. {
  1063. static bstring b;
  1064. #if TEST_BSTRING
  1065. static int init = FALSE;
  1066. if ( init == FALSE )
  1067. {
  1068. sprintf( b.name, "<exp_getsval() bstring>" );
  1069. }
  1070. #endif
  1071. b.rab = FALSE;
  1072. /* return based on operation type */
  1073. switch( e->operation )
  1074. {
  1075. case CONST_STRING:
  1076. case OP_STRJOIN:
  1077. return &( e->sval );
  1078. case VARIABLE:
  1079. switch( e->type )
  1080. {
  1081. case STRING:
  1082. return var_findsval( e->xvar, e->array_pos );
  1083. case NUMBER:
  1084. sprintf( bwb_ebuf, "%lf ", (double) exp_getnval( e ) );
  1085. str_ctob( &b, bwb_ebuf );
  1086. return &b;
  1087. default:
  1088. #if PROG_ERRORS
  1089. sprintf( bwb_ebuf, "in exp_getsval(): type <%c> inappropriate for NUMBER",
  1090. e->type );
  1091. bwb_error( bwb_ebuf );
  1092. #else
  1093. bwb_error( err_syntax );
  1094. #endif
  1095. return NULL;
  1096. }
  1097. break;
  1098. case NUMBER:
  1099. switch( e->type )
  1100. {
  1101. case NUMBER:
  1102. sprintf( bwb_ebuf, "%lf ", (double) exp_getnval( e ) );
  1103. str_ctob( &b, bwb_ebuf );
  1104. return &b;
  1105. default:
  1106. #if PROG_ERRORS
  1107. sprintf( bwb_ebuf, "in exp_getsval(): type <%c> inappropriate for NUMBER",
  1108. e->type );
  1109. bwb_error( bwb_ebuf );
  1110. #else
  1111. bwb_error( err_syntax );
  1112. #endif
  1113. return NULL;
  1114. }
  1115. break;
  1116. default:
  1117. #if PROG_ERRORS
  1118. sprintf( bwb_ebuf, "in exp_getsval(): operation <%d> inappropriate",
  1119. e->operation );
  1120. bwb_error( bwb_ebuf );
  1121. #else
  1122. bwb_error( err_syntax );
  1123. #endif
  1124. return NULL;
  1125. }
  1126. /* this point may not be reached */
  1127. return NULL;
  1128. }
  1129. /***************************************************************
  1130. FUNCTION: inc_esc()
  1131. DESCRIPTION: This function increments the expression
  1132. stack counter.
  1133. ***************************************************************/
  1134. #if ANSI_C
  1135. int
  1136. inc_esc( void )
  1137. #else
  1138. int
  1139. inc_esc()
  1140. #endif
  1141. {
  1142. #if INTENSIVE_DEBUG
  1143. sprintf( bwb_ebuf, "in inc_esc(): prev level <%d>",
  1144. CURTASK expsc );
  1145. bwb_debug ( bwb_ebuf );
  1146. #endif
  1147. ++CURTASK expsc;
  1148. if ( CURTASK expsc >= ESTACKSIZE )
  1149. {
  1150. --CURTASK expsc;
  1151. #if PROG_ERRORS
  1152. sprintf( bwb_ebuf, "in inc_esc(): Maximum expression stack exceeded <%d>",
  1153. CURTASK expsc );
  1154. bwb_error( bwb_ebuf );
  1155. #else
  1156. bwb_error( err_overflow );
  1157. #endif
  1158. return OP_NULL;
  1159. }
  1160. #if INTENSIVE_DEBUG
  1161. sprintf( CURTASK exps[ CURTASK expsc ].string, "New Expression Stack Level %d", CURTASK expsc );
  1162. #endif
  1163. CURTASK exps[ CURTASK expsc ].type = NUMBER;
  1164. CURTASK exps[ CURTASK expsc ].operation = OP_NULL;
  1165. CURTASK exps[ CURTASK expsc ].pos_adv = 0;
  1166. return TRUE;
  1167. }
  1168. /***************************************************************
  1169. FUNCTION: dec_esc()
  1170. DESCRIPTION: This function decrements the expression
  1171. stack counter.
  1172. ***************************************************************/
  1173. #if ANSI_C
  1174. int
  1175. dec_esc( void )
  1176. #else
  1177. int
  1178. dec_esc()
  1179. #endif
  1180. {
  1181. --CURTASK expsc;
  1182. if ( CURTASK expsc < 0 )
  1183. {
  1184. CURTASK expsc = 0;
  1185. #if PROG_ERRORS
  1186. sprintf( bwb_ebuf, "in dec_esc(): Expression stack counter < 0." );
  1187. bwb_error( bwb_ebuf );
  1188. #else
  1189. bwb_error( err_overflow );
  1190. #endif
  1191. return OP_NULL;
  1192. }
  1193. return TRUE;
  1194. }