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.
 
 
 
 
 
 

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