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.
 
 
 
 
 
 

1308 lines
32 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. /* Those additionally marked with "DD" were at the suggestion of */
  22. /* Dale DePriest (daled@cadence.com). */
  23. /* */
  24. /* Version 3.00 by Howard Wulf, AF5NE */
  25. /* */
  26. /*---------------------------------------------------------------*/
  27. #include "bwbasic.h"
  28. /***************************************************************
  29. FUNCTION: bwb_exp()
  30. DESCRIPTION: This is the function by which the expression
  31. parser is called.
  32. ***************************************************************/
  33. struct exp_ese *
  34. bwb_exp(char *expression, int assignment, int *position)
  35. {
  36. struct exp_ese *rval; /* return value */
  37. int entry_level, main_loop, err_condition;
  38. int r; /* return value from functions */
  39. register int c; /* quick counter */
  40. bwx_DEBUG(__FUNCTION__);
  41. /* save the entry level of the expression stack in order to check it
  42. * at the end of this function */
  43. entry_level = CURTASK expsc;
  44. err_condition = FALSE;
  45. /* advance past whitespace */
  46. adv_ws(expression, position);
  47. /* increment the expression stack counter to get a new level */
  48. inc_esc();
  49. /* check to be sure there is a legitimate expression and set initial
  50. * parameters for the main loop */
  51. if (is_eol(expression, position) == TRUE)
  52. {
  53. main_loop = FALSE; /* break out of loop */
  54. }
  55. else
  56. {
  57. main_loop = TRUE;
  58. CURTASK exps[CURTASK expsc].pos_adv = 0;
  59. }
  60. /* main parsing loop */
  61. while (main_loop == TRUE)
  62. {
  63. char *e; /* pointer to current string */
  64. /* set variable <e> to the start of the expression */
  65. e = &(expression[*position]);
  66. /* detect the operation required at this level */
  67. CURTASK exps[CURTASK expsc].operation = exp_findop(e);
  68. /* perform actions specific to the operation */
  69. switch (CURTASK exps[CURTASK expsc].operation)
  70. {
  71. case OP_ERROR:
  72. main_loop = FALSE;
  73. err_condition = TRUE;
  74. break;
  75. case OP_TERMINATE: /* terminate at THEN, ELSE, TO */
  76. case OP_STRJOIN: /* string join or tab */
  77. case OP_STRTAB:
  78. main_loop = FALSE;
  79. err_condition = FALSE;
  80. dec_esc();
  81. break;
  82. case OP_ADD: /* in the case of any numerical operation, */
  83. case OP_SUBTRACT:
  84. case OP_MULTIPLY:
  85. case OP_DIVIDE:
  86. case OP_MODULUS:
  87. case OP_EXPONENT:
  88. case OP_INTDIVISION:
  89. case OP_GREATERTHAN:
  90. case OP_LESSTHAN:
  91. case OP_GTEQ:
  92. case OP_LTEQ:
  93. case OP_NOTEQUAL:
  94. case OP_NOT:
  95. case OP_AND:
  96. case OP_OR:
  97. case OP_XOR:
  98. case OP_IMPLIES:
  99. case OP_EQUIV:
  100. case OP_NEGATION: /* JBV */
  101. case OP_POSATION:
  102. CURTASK exps[CURTASK expsc].pos_adv = -1; /* set to strange number */
  103. /* cycle through operator table to find match */
  104. for (c = 0; c < NUM_OPERATORS; ++c)
  105. {
  106. if (exp_ops[c].operation == CURTASK exps[CURTASK expsc].operation)
  107. {
  108. CURTASK exps[CURTASK expsc].pos_adv = strlen(exp_ops[c].symbol);
  109. }
  110. }
  111. if (CURTASK exps[CURTASK expsc].pos_adv == -1) /* was a match found? */
  112. {
  113. CURTASK exps[CURTASK expsc].pos_adv = 0; /* no -- set to 0 */
  114. }
  115. break; /* and move on */
  116. case OP_EQUALS:
  117. if (assignment == TRUE)
  118. {
  119. CURTASK exps[CURTASK expsc].operation = OP_ASSIGN;
  120. }
  121. CURTASK exps[CURTASK expsc].pos_adv = 1;
  122. break;
  123. case PARENTHESIS:
  124. r = exp_paren(e);
  125. break;
  126. case CONST_STRING:
  127. r = exp_strconst(e);
  128. break;
  129. case CONST_NUMERICAL:
  130. r = exp_numconst(e);
  131. break;
  132. case FUNCTION:
  133. r = exp_function(e);
  134. break;
  135. case VARIABLE:
  136. r = exp_variable(e);
  137. break;
  138. default:
  139. err_condition = TRUE;
  140. main_loop = FALSE;
  141. sprintf(bwb_ebuf, "in bwb_exp.c:bwb_exp(): unidentified operation (%d).",
  142. CURTASK exps[CURTASK expsc].operation);
  143. bwb_error(bwb_ebuf);
  144. break;
  145. }
  146. /* increment *position counter based on previous actions */
  147. *position += CURTASK exps[CURTASK expsc].pos_adv;
  148. CURTASK exps[CURTASK expsc].pos_adv = 0; /* reset advance counter */
  149. /* check for end of string */
  150. if (is_eol(expression, position) == TRUE)
  151. {
  152. main_loop = FALSE; /* break out of loop */
  153. }
  154. /* get a new stack level before looping */
  155. if (main_loop == TRUE)
  156. {
  157. r = inc_esc();
  158. }
  159. /* check for error return */
  160. if (r == OP_ERROR)
  161. {
  162. main_loop = FALSE;
  163. err_condition = TRUE;
  164. }
  165. else
  166. {
  167. r = TRUE;
  168. }
  169. } /* end of main parsing loop */
  170. /* check error condition */
  171. if (err_condition == TRUE)
  172. {
  173. /* decrement the expression stack counter until it matches
  174. * entry_level */
  175. while (CURTASK expsc > entry_level)
  176. {
  177. dec_esc();
  178. }
  179. bwb_error(err_syntax);
  180. return NULL;
  181. }
  182. /* no error; normal exit from function */
  183. else
  184. {
  185. /* are any more operations needed? if we are still at entry
  186. * level, then they are not */
  187. /* try operations */
  188. exp_operation(entry_level);
  189. /* see what is on top of the stack */
  190. if (CURTASK expsc > (entry_level + 1))
  191. {
  192. switch (CURTASK exps[CURTASK expsc].operation)
  193. {
  194. case OP_STRJOIN:
  195. if (CURTASK expsc != (entry_level + 2))
  196. {
  197. sprintf(bwb_ebuf, "in bwb_exp(): OP_STRJOIN in wrong position.");
  198. bwb_error(bwb_ebuf);
  199. }
  200. break;
  201. default:
  202. sprintf(bwb_ebuf, "in bwb_exp(): incomplete expression.");
  203. bwb_error(bwb_ebuf);
  204. break;
  205. }
  206. /* decrement the expression stack counter */
  207. dec_esc();
  208. }
  209. /* assign rvar to the variable for the current level */
  210. rval = &(CURTASK exps[CURTASK expsc]);
  211. /* decrement the expression stack counter */
  212. dec_esc();
  213. /* check the current level before exit */
  214. if (entry_level != CURTASK expsc)
  215. {
  216. sprintf(bwb_ebuf, "in bwb_exp(): exit stack level (%d) does not match entry stack level (%d)",
  217. CURTASK expsc, entry_level);
  218. bwb_error(bwb_ebuf);
  219. }
  220. }
  221. /* return a pointer to the last stack level */
  222. return rval;
  223. }
  224. /***************************************************************
  225. FUNCTION: exp_findop()
  226. DESCRIPTION: This function reads the expression to find
  227. what operation is required at its stack level.
  228. ***************************************************************/
  229. int
  230. exp_findop(char *expression)
  231. {
  232. register int c; /* character counter */
  233. int rval; /* return value */
  234. char cbuf[BasicStringLengthMax + 1]; /* capitalized
  235. * expression */
  236. char nbuf[BasicStringLengthMax + 1]; /* non-capitalized
  237. * expression */
  238. int position; /* position in the expression */
  239. int adv_loop; /* control loop to build expression */
  240. int LastPosition;
  241. bwx_DEBUG(__FUNCTION__);
  242. /* set return value to OP_NULL initially */
  243. rval = OP_NULL;
  244. /* assign local pointer to expression to begin reading */
  245. position = 0;
  246. /* advance to the first significant character */
  247. adv_ws(expression, &position);
  248. /* we now have the first significant character and can begin parsing */
  249. /* check the first character for an indication of a parenthetical
  250. * expression, a string constant, or a numerical constant that begins
  251. * with a digit (numerical constants beginning with a plus or minus
  252. * sign or hex/octal/binary constants will have to be detected by
  253. * exp_isnc() */
  254. switch (expression[position])
  255. {
  256. case '=':
  257. /* look-ahead one character */
  258. switch( expression[position + 1] )
  259. {
  260. case '>':
  261. /* => */
  262. rval = OP_GTEQ;
  263. break;
  264. case '<':
  265. /* =< */
  266. rval = OP_LTEQ;
  267. break;
  268. default:
  269. rval = OP_EQUALS;
  270. break;
  271. }
  272. break;
  273. case '<':
  274. /* look-ahead one character */
  275. switch( expression[position + 1] )
  276. {
  277. case '>':
  278. /* <> */
  279. rval = OP_NOTEQUAL;
  280. break;
  281. case '=':
  282. /* <= */
  283. rval = OP_LTEQ;
  284. break;
  285. default:
  286. rval = OP_LESSTHAN;
  287. break;
  288. }
  289. break;
  290. case '>':
  291. /* look-ahead one character */
  292. switch( expression[position + 1] )
  293. {
  294. case '=':
  295. /* >= */
  296. rval = OP_GTEQ;
  297. break;
  298. case '<':
  299. /* >< */
  300. rval = OP_NOTEQUAL;
  301. break;
  302. default:
  303. rval = OP_GREATERTHAN;
  304. break;
  305. }
  306. break;
  307. case '\"': /* this should indicate a string constant */
  308. rval = CONST_STRING;
  309. break;
  310. case '(': /* this will indicate a simple parenthetical
  311. * expression */
  312. rval = PARENTHESIS;
  313. break;
  314. case ')': /* end of argument list? */
  315. rval = OP_TERMINATE;
  316. break;
  317. case '0': /* these will indicate a numerical constant */
  318. case '1':
  319. case '2':
  320. case '3':
  321. case '4':
  322. case '5':
  323. case '6':
  324. case '7':
  325. case '8':
  326. case '9':
  327. case '.':
  328. case '&': /* designator for hex or octal constant */
  329. rval = CONST_NUMERICAL;
  330. break;
  331. }
  332. if (rval != OP_NULL)
  333. {
  334. return rval;
  335. }
  336. /* String constants, numerical constants, open parentheses, and the
  337. * plus and minus operators have been checked at this point; but if
  338. * the return value is still OP_NULL, other possibilities must be
  339. * checked, namely, other operators, function names, and variable
  340. * names. The function adv_element cannot be used here because it
  341. * will stop, e.g., with certain operators and not include them in
  342. * the returned element. */
  343. /* get a character string to be interpreted */
  344. adv_loop = TRUE;
  345. cbuf[0] = '\0';
  346. nbuf[0] = '\0';
  347. c = 0;
  348. while (adv_loop == TRUE)
  349. {
  350. switch (expression[position])
  351. {
  352. case ' ': /* whitespace */
  353. case '\0': /* end of string */
  354. case '(': /* parenthesis terminating function name */
  355. adv_loop = FALSE;
  356. break;
  357. default:
  358. nbuf[c] = cbuf[c] = expression[position];
  359. ++c;
  360. nbuf[c] = cbuf[c] = '\0';
  361. ++position;
  362. break;
  363. }
  364. LastPosition = position;
  365. if (c > BasicStringLengthMax)
  366. {
  367. adv_loop = FALSE;
  368. }
  369. }
  370. /* check for numerical constant */
  371. rval = exp_isnc(cbuf);
  372. if (rval != OP_NULL)
  373. {
  374. return rval;
  375. }
  376. /* check for other operators */
  377. rval = exp_isop(cbuf);
  378. if (rval != OP_NULL)
  379. {
  380. return rval;
  381. }
  382. exp_getvfname(cbuf, nbuf);
  383. if (strlen(nbuf) == 0)
  384. {
  385. return OP_ERROR;
  386. }
  387. strcpy(CURTASK exps[CURTASK expsc].string, nbuf);
  388. /* User definedfunctions are now processed by fnc_deffn */
  389. if (rval != OP_NULL)
  390. {
  391. return rval;
  392. }
  393. /* check for function name */
  394. rval = exp_isfn(nbuf);
  395. if (rval != OP_NULL)
  396. {
  397. return rval;
  398. }
  399. /* check for a BASIC command, esp. to catch THEN or ELSE */
  400. rval = exp_iscmd(nbuf);
  401. if (rval != OP_NULL)
  402. {
  403. return rval;
  404. }
  405. /* last: check for variable name, and assign it if there is not
  406. * already one */
  407. /* OPTION STRICT OFF to disables Implicit DIM */
  408. /* This is only for ECMA-55. ECMA-116 requires arrays to be
  409. * dimensioned prior to being used. */
  410. if (strlen(nbuf) == strlen(cbuf))
  411. {
  412. if (bwb_isvar(nbuf) == FALSE)
  413. {
  414. /* not an existing variable */
  415. while (expression[LastPosition] == ' ')
  416. {
  417. LastPosition++;
  418. }
  419. if (expression[LastPosition] == '(')
  420. {
  421. /* MUST be a dynamically created array, LET
  422. * ... A(10) ... ' variable "A" has NOT been
  423. * dimensioned */
  424. int NumDimensions;
  425. NumDimensions = DetermineNumberOfDimensions(expression, LastPosition);
  426. if (NumDimensions < 1)
  427. {
  428. bwb_error(err_incomplete);
  429. return OP_ERROR;
  430. }
  431. if (ImplicitDim(nbuf, NumDimensions) != TRUE)
  432. {
  433. bwb_error(err_syntax);
  434. return OP_ERROR;
  435. }
  436. } /* if( expression[ LastPosition ] == '(' ) */
  437. } /* if( bwb_isvar( nbuf ) == FALSE ) */
  438. } /* if( strlen( nbuf ) == strlen( cbuf ) ) */
  439. rval = exp_isvn(nbuf);
  440. if (rval != OP_NULL)
  441. {
  442. return rval;
  443. }
  444. /* return the value assigned (or OP_ERROR if none assigned) */
  445. return OP_ERROR;
  446. }
  447. /***************************************************************
  448. FUNCTION: exp_isnc()
  449. DESCRIPTION: This function reads the expression to find
  450. if a numerical constant is present at this
  451. point.
  452. ***************************************************************/
  453. int
  454. exp_isnc(char *expression)
  455. {
  456. bwx_DEBUG(__FUNCTION__);
  457. switch (expression[0])
  458. {
  459. case '0': /* these will indicate a numerical constant */
  460. case '1':
  461. case '2':
  462. case '3':
  463. case '4':
  464. case '5':
  465. case '6':
  466. case '7':
  467. case '8':
  468. case '9':
  469. case '&': /* indicator for hex or octal constant */
  470. return CONST_NUMERICAL;
  471. case '-':
  472. switch (CURTASK exps[CURTASK expsc - 1].operation)
  473. {
  474. case VARIABLE: /* external variable pointed to by xvar */
  475. if (TRUE)
  476. {
  477. struct bwb_variable *v;
  478. v = CURTASK exps[CURTASK expsc - 1].xvar;
  479. if (v->IsInDim > 0)
  480. {
  481. return OP_NEGATION;
  482. }
  483. }
  484. case NUMBER: /* number held as internal variable in uvar */
  485. case CONST_STRING: /* string constant */
  486. case CONST_NUMERICAL: /* numerical constant */
  487. /* might be subtraction */
  488. return OP_NULL;
  489. }
  490. /* any arithmetic operator: +, -, *, /, \, MOD */
  491. /* any logical operator: AND, OR, XOR, IMP, EQV, NOT */
  492. /* any comparison operator: <, <=, =, >=, > */
  493. /* assignment: LET A = - .... */
  494. /* parenthesis: LET A = ... (- .... */
  495. /* command: PRINT - .... */
  496. return OP_NEGATION;
  497. case '+':
  498. case BasicFileNumberPrefix: /* EOF( #1 ) */
  499. switch (CURTASK exps[CURTASK expsc - 1].operation)
  500. {
  501. case VARIABLE: /* external variable pointed to by xvar */
  502. if (TRUE)
  503. {
  504. struct bwb_variable *v;
  505. v = CURTASK exps[CURTASK expsc - 1].xvar;
  506. if (v->IsInDim > 0)
  507. {
  508. return OP_POSATION;
  509. }
  510. }
  511. case NUMBER: /* number held as internal variable in uvar */
  512. case CONST_STRING: /* string constant */
  513. case CONST_NUMERICAL: /* numerical constant */
  514. /* might be addition */
  515. return OP_NULL;
  516. }
  517. /* any arithmetic operator: +, -, *, /, \, MOD */
  518. /* any logical operator: AND, OR, XOR, IMP, EQV, NOT */
  519. /* any comparison operator: <, <=, =, >=, > */
  520. /* assignment: LET A = + .... */
  521. /* parenthesis: LET A = ... (+ .... */
  522. /* command: PRINT + .... */
  523. return OP_POSATION;
  524. default:
  525. return OP_NULL;
  526. }
  527. }
  528. /***************************************************************
  529. FUNCTION: exp_isop()
  530. DESCRIPTION: This function reads the expression to find
  531. if a logical or mathematical operation is
  532. required at this point.
  533. This function presupposes that a numerical constant with
  534. affixed plus or minus sign has been ruled out.
  535. ***************************************************************/
  536. int
  537. exp_isop(char *expression)
  538. {
  539. /* Problem: The following lines are valid BASIC: LET note = 0 LET
  540. * not1 = 0 LET andy = 0 LET and2 = 0 LET oreo = 0 LET or3 = 0 LET
  541. * xorigin = 0 LET xor4 = 0 LET imply = 0 LET impl5 = 0 LET equality
  542. * = 0 LET equ6 = 0 LET mode = 0 LET mod7 = 0 However, the
  543. * interpreter displays the message: ERROR: in exp_getnval():
  544. * operation <0> is not a number */
  545. /* Reference: ECMA-116, Page 15, Section 4.1.2, Last Paragraph All
  546. * keywords in a program, when used as such, shall be preceded and
  547. * followed by some character other than a letter, digit, underline
  548. * or dollar-sign. A keyword may also be followed by an end-of-line */
  549. int i;
  550. int j;
  551. int k;
  552. int Found;
  553. register int c; /* counter */
  554. bwx_DEBUG(__FUNCTION__);
  555. /* compare the initial characters of the string with the table of
  556. * operators */
  557. for (c = 0; c < NUM_OPERATORS; ++c)
  558. {
  559. if (OptionVersion & exp_ops[c].OptionVersionBitmask)
  560. if (strncasecmp(expression, exp_ops[c].symbol,
  561. (size_t) strlen(exp_ops[c].symbol)) == 0)
  562. {
  563. /* Problem: The following lines are valid
  564. * BASIC: LET note = 0 LET not1 = 0 LET andy
  565. * = 0 LET and2 = 0 LET oreo = 0 LET or3 = 0
  566. * LET xorigin = 0 LET xor4 = 0 LET imply = 0
  567. * LET impl5 = 0 LET equality = 0 LET equ6 =
  568. * 0 LET mode = 0 LET mod7 = 0
  569. *
  570. * However, the interpreter displays the
  571. * message: ERROR: in exp_getnval():
  572. * operation <0> is not a number */
  573. /* Reference: ECMA-116, Page 15, Section
  574. * 4.1.2, Last Paragraph All keywords in a
  575. * program, when used as such, shall be
  576. * preceded and followed by some character
  577. * other than a letter, digit, underline or
  578. * dollar-sign. A keyword may also be
  579. * followed by an end-of-line */
  580. Found = TRUE;
  581. if (isalpha(exp_ops[c].symbol[0]))
  582. {
  583. /* NOT, AND, OR, XOR, IMP, EQV, MOD */
  584. i = strlen(exp_ops[c].symbol);
  585. j = strlen(expression);
  586. if (j > i)
  587. {
  588. /* the expression does not
  589. * end with the end of the
  590. * operator */
  591. k = expression[i];
  592. /* character AFTER the
  593. * operator */
  594. if (isalpha(k))
  595. {
  596. /* NOTe, ANDy, OReo,
  597. * XORe, IMPly,
  598. * EQUals, MODe */
  599. Found = FALSE;
  600. }
  601. else
  602. if (isdigit(k))
  603. {
  604. /* NOT1, AND2, OR3,
  605. * XOR4, IMP5, EQU6,
  606. * MOD7 */
  607. Found = FALSE;
  608. }
  609. else
  610. if (k == BasicStringSuffix)
  611. {
  612. /* N O T $ ,
  613. *
  614. * AN D $ ,
  615. *
  616. * OR $ ,
  617. *
  618. * XO R $ ,
  619. *
  620. * IM P $ ,
  621. *
  622. * EQ U $ ,
  623. *
  624. * MO D $ */
  625. Found = FALSE;
  626. }
  627. else
  628. if( OptionFlags & OPTION_BUGS_ON )
  629. {
  630. if (k == '_' || k == '.' )
  631. {
  632. /* NOT _, AND _, OR_
  633. * , XOR _, IMP _,
  634. * EQU _, MOD _ */
  635. Found = FALSE;
  636. }
  637. }
  638. else
  639. {
  640. /* N O T ,
  641. *
  642. * AN D ,
  643. *
  644. * OR ,
  645. *
  646. * XO R ,
  647. *
  648. * IM P ,
  649. *
  650. * EQ U ,
  651. *
  652. * MO D */
  653. }
  654. }
  655. }
  656. if (Found == TRUE)
  657. {
  658. return exp_ops[c].operation;
  659. }
  660. }
  661. }
  662. /* search failed; return OP_NULL */
  663. return OP_NULL;
  664. }
  665. /***************************************************************
  666. FUNCTION: exp_iscmd()
  667. DESCRIPTION: This function reads the expression to find
  668. if a BASIC command name is present; if so,
  669. it returns OP_TERMINATE to terminate expression
  670. parsing. This is critical, for example, in
  671. parsing a conditional following IF where THEN,
  672. ELSE, and other BASIC commands may follow.
  673. ***************************************************************/
  674. int
  675. exp_iscmd(char *expression)
  676. {
  677. register int n;
  678. bwx_DEBUG(__FUNCTION__);
  679. /* FIXME: extract the expression before calling bwb_exp() - no COMMANDS should be there */
  680. /* This should be a Syntax Error */
  681. /* first check for likely statements */
  682. if (strcasecmp(expression, "THEN") == 0)
  683. {
  684. /* IF ... THEN */
  685. return OP_TERMINATE;
  686. }
  687. if (strcasecmp(expression, "TO") == 0)
  688. {
  689. /* FOR X =... TO ... STEP */
  690. return OP_TERMINATE;
  691. }
  692. if (strcasecmp(expression, "STEP") == 0)
  693. {
  694. /* FOR X =... TO ... STEP */
  695. return OP_TERMINATE;
  696. }
  697. if (strcasecmp(expression, "GO") == 0)
  698. {
  699. /* ON ... GO */
  700. return OP_TERMINATE;
  701. }
  702. if (strcasecmp(expression, "GOTO") == 0)
  703. {
  704. /* ON ... GOTO */
  705. return OP_TERMINATE;
  706. }
  707. if (strcasecmp(expression, "GOSUB") == 0)
  708. {
  709. /* ON ... GOSUB */
  710. return OP_TERMINATE;
  711. }
  712. /* run through the command table and search for a match */
  713. n = is_cmd(expression);
  714. if (n > 0)
  715. {
  716. /* FIXME: this should return OP_ERROR, since we found an
  717. * UNEXPECTED command */
  718. return OP_TERMINATE;
  719. }
  720. /* search failed, return NULL */
  721. return OP_NULL;
  722. }
  723. /***************************************************************
  724. FUNCTION: exp_isfn()
  725. DESCRIPTION: This function reads the expression to find
  726. if a function name is present at this point.
  727. ***************************************************************/
  728. int
  729. exp_isfn(char *expression)
  730. {
  731. /* if we are in a USER DEFINED FUNCTION - END FUNCTION block, the
  732. * function name is a local variable */
  733. int i;
  734. bwx_DEBUG(__FUNCTION__);
  735. for (i = CURTASK exsc; i >= 0; i--)
  736. {
  737. if (CURTASK excs[i].LoopTopLine != NULL)
  738. {
  739. if (CURTASK excs[i].LoopTopLine->cmdnum == C_FUNCTION)
  740. {
  741. if (CURTASK excs[i].local_variable != NULL)
  742. {
  743. if (strcasecmp(CURTASK excs[i].local_variable->name, expression) == 0)
  744. {
  745. return VARIABLE;
  746. }
  747. }
  748. }
  749. }
  750. }
  751. if (fnc_find(expression) != NULL)
  752. {
  753. return FUNCTION;
  754. }
  755. return OP_NULL;
  756. }
  757. /***************************************************************
  758. FUNCTION: exp_isvn()
  759. DESCRIPTION: This function reads the expression to find
  760. if a variable name at this point.
  761. ***************************************************************/
  762. int
  763. exp_isvn(char *expression)
  764. {
  765. bwx_DEBUG(__FUNCTION__);
  766. if (var_find(expression) != NULL)
  767. {
  768. return VARIABLE;
  769. }
  770. return OP_NULL;
  771. }
  772. /***************************************************************
  773. FUNCTION: exp_getvfname()
  774. DESCRIPTION: This function reads the expression to find
  775. a variable or function name at this point.
  776. ***************************************************************/
  777. int
  778. exp_getvfname(char *source, char *destination)
  779. {
  780. #if 0
  781. int s_pos, d_pos; /* source, destination positions */
  782. bwx_DEBUG(__FUNCTION__);
  783. s_pos = d_pos = 0;
  784. destination[0] = '\0';
  785. while (source[s_pos] != '\0')
  786. {
  787. /* all alphabetical characters are acceptable */
  788. if (isalpha(source[s_pos]) != 0)
  789. {
  790. destination[d_pos] = source[s_pos];
  791. ++d_pos;
  792. ++s_pos;
  793. destination[d_pos] = '\0';
  794. }
  795. /* numerical characters are acceptable but not in the first
  796. * position */
  797. else
  798. if ((isdigit(source[s_pos]) != 0) && (d_pos != 0))
  799. {
  800. destination[d_pos] = source[s_pos];
  801. ++d_pos;
  802. ++s_pos;
  803. destination[d_pos] = '\0';
  804. }
  805. /* other characters will have to be tried on their own merits */
  806. else
  807. {
  808. switch (source[s_pos])
  809. {
  810. case '.': /* tolerated non-alphabetical
  811. * characters */
  812. case '_':
  813. destination[d_pos] = source[s_pos];
  814. ++d_pos;
  815. ++s_pos;
  816. destination[d_pos] = '\0';
  817. break;
  818. case STRING: /* terminating characters */
  819. case BasicDoubleSuffix: /* Microsoft-type
  820. * precision indicator;
  821. * ignored but
  822. * terminates */
  823. case BasicSingleSuffix: /* Microsoft-type
  824. * precision indicator;
  825. * ignored but
  826. * terminates */
  827. case BasicCurrencySuffix: /* Microsoft-type
  828. * precision indicator;
  829. * ignored but
  830. * terminates */
  831. case BasicLongSuffix: /* Microsoft-type precision
  832. * indicator; ignored but
  833. * terminates */
  834. case BasicIntegerSuffix: /* Microsoft-type
  835. * precision indicator;
  836. * ignored but
  837. * terminates */
  838. destination[d_pos] = source[s_pos];
  839. ++d_pos;
  840. ++s_pos;
  841. destination[d_pos] = '\0';
  842. return TRUE;
  843. case '(': /* begin function/sub name */
  844. return TRUE;
  845. default: /* anything else is non-tolerated */
  846. return FALSE;
  847. }
  848. }
  849. }
  850. return TRUE; /* exit after coming to the end */
  851. #endif
  852. int position = 0;
  853. bwb_getvarname( source, destination, &position);
  854. return TRUE; /* exit after coming to the end */
  855. }
  856. /***************************************************************
  857. FUNCTION: exp_validarg()
  858. DESCRIPTION: This function reads the expression to
  859. determine whether it is a valid argument (to be
  860. read recursively by bwb_exp() and passed to a
  861. function.
  862. ***************************************************************/
  863. int
  864. exp_validarg(char *expression)
  865. {
  866. register int c;
  867. bwx_DEBUG(__FUNCTION__);
  868. c = 0;
  869. while (TRUE)
  870. {
  871. switch (expression[c])
  872. {
  873. case ' ':
  874. ++c;
  875. break;
  876. case '\0':
  877. return FALSE;
  878. default:
  879. return TRUE;
  880. }
  881. }
  882. }
  883. /***************************************************************
  884. FUNCTION: exp_getnval()
  885. DESCRIPTION: This function returns the numerical value
  886. contain in the expression-stack element
  887. pointed to by 'e'.
  888. ***************************************************************/
  889. double
  890. exp_getnval(struct exp_ese * e)
  891. {
  892. BasicNumberType Value;
  893. bwx_DEBUG(__FUNCTION__);
  894. Value = 0;
  895. if (e->type == NUMBER)
  896. {
  897. switch (e->operation)
  898. {
  899. case VARIABLE:
  900. Value = (*var_findnval(e->xvar, e->array_pos));
  901. break;
  902. case NUMBER:
  903. Value = e->nval;
  904. break;
  905. default:
  906. bwb_error(err_syntax);
  907. }
  908. }
  909. else
  910. {
  911. bwb_error(err_mismatch);
  912. }
  913. Value = VerifyNumeric(Value);
  914. return Value;
  915. }
  916. int
  917. exp_getival(struct exp_ese * e)
  918. {
  919. double XR;
  920. XR = rint(exp_getnval(e));
  921. if (XR < INT_MIN)
  922. {
  923. bwb_Warning_Overflow("*** Arithmetic Overflow ***");
  924. XR = INT_MIN;
  925. }
  926. else
  927. if (XR > INT_MAX)
  928. {
  929. bwb_Warning_Overflow("*** Arithmetic Overflow ***");
  930. XR = INT_MAX;
  931. }
  932. return (int) XR;
  933. }
  934. /***************************************************************
  935. FUNCTION: exp_getsval()
  936. DESCRIPTION: This function returns a pointer to the
  937. BASIC string structure pointed to by
  938. expression-stack element 'e'.
  939. ***************************************************************/
  940. bstring *
  941. exp_getsval(struct exp_ese * e)
  942. {
  943. static bstring b;
  944. bwx_DEBUG(__FUNCTION__);
  945. b.rab = FALSE;
  946. /* return based on operation type */
  947. switch (e->operation)
  948. {
  949. case CONST_STRING:
  950. case OP_STRJOIN:
  951. return &(e->sval);
  952. case VARIABLE:
  953. switch (e->type)
  954. {
  955. case STRING:
  956. return var_findsval(e->xvar, e->array_pos);
  957. case NUMBER:
  958. sprintf(bwb_ebuf, BasicNumberPrintFormat " ", exp_getnval(e));
  959. str_ctob(&b, bwb_ebuf);
  960. return &b;
  961. default:
  962. sprintf(bwb_ebuf, "in exp_getsval(): type <%c> inappropriate for NUMBER",
  963. e->type);
  964. bwb_error(bwb_ebuf);
  965. return NULL;
  966. }
  967. break;
  968. case NUMBER:
  969. switch (e->type)
  970. {
  971. case NUMBER:
  972. sprintf(bwb_ebuf, BasicNumberPrintFormat " ", exp_getnval(e));
  973. str_ctob(&b, bwb_ebuf);
  974. return &b;
  975. default:
  976. sprintf(bwb_ebuf, "in exp_getsval(): type <%c> inappropriate for NUMBER",
  977. e->type);
  978. bwb_error(bwb_ebuf);
  979. return NULL;
  980. }
  981. break;
  982. default:
  983. sprintf(bwb_ebuf, "in exp_getsval(): operation <%d> inappropriate",
  984. e->operation);
  985. bwb_error(bwb_ebuf);
  986. return NULL;
  987. }
  988. /* this point may not be reached */
  989. return NULL;
  990. }
  991. /***************************************************************
  992. FUNCTION: inc_esc()
  993. DESCRIPTION: This function increments the expression
  994. stack counter.
  995. ***************************************************************/
  996. int
  997. inc_esc(void)
  998. {
  999. bwx_DEBUG(__FUNCTION__);
  1000. ++CURTASK expsc;
  1001. if (CURTASK expsc >= ESTACKSIZE)
  1002. {
  1003. --CURTASK expsc;
  1004. sprintf(bwb_ebuf, "in inc_esc(): Maximum expression stack exceeded <%d>",
  1005. CURTASK expsc);
  1006. bwb_error(bwb_ebuf);
  1007. return OP_NULL;
  1008. }
  1009. CURTASK exps[CURTASK expsc].type = NUMBER;
  1010. CURTASK exps[CURTASK expsc].operation = OP_NULL;
  1011. CURTASK exps[CURTASK expsc].pos_adv = 0;
  1012. return TRUE;
  1013. }
  1014. /***************************************************************
  1015. FUNCTION: dec_esc()
  1016. DESCRIPTION: This function decrements the expression
  1017. stack counter.
  1018. ***************************************************************/
  1019. int
  1020. dec_esc(void)
  1021. {
  1022. bwx_DEBUG(__FUNCTION__);
  1023. --CURTASK expsc;
  1024. if (CURTASK expsc < 0)
  1025. {
  1026. CURTASK expsc = 0;
  1027. sprintf(bwb_ebuf, "in dec_esc(): Expression stack counter < 0.");
  1028. bwb_error(bwb_ebuf);
  1029. return OP_NULL;
  1030. }
  1031. return TRUE;
  1032. }
  1033. /* EOF */