tiny.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. /*
  2. NAME
  3. tiny.c -- interpreter for the Tiny programming language
  4. DESCRIPTION
  5. This is an entire ANSI C89 program that interprets programs written
  6. in the language Tiny.
  7. LICENSE TERMS
  8. Copyright (C) 2006 Ron Hudson
  9. This program is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. ****************************************************************************/
  21. /*
  22. ** Tiny - A small Basic like RPN language
  23. ** See tiny.html for syntax details and examples
  24. **
  25. ** Version History
  26. ** 0.0.1 Begin keeping a verion history 6-june-2006
  27. ** Moved Gatherformat code to inside if not string print part
  28. ** becuase printing a single qoute should not be a problem.
  29. ** (By the theory that if you are printing you aren't doing
  30. ** anything else
  31. **
  32. ** 0.1.0 Changed by Alex Smith: delinting, change to dynamic 6-june-2006
  33. ** memory, automatic pretty-printing. The changes are
  34. ** marked AIS in comments, apart from the automatic
  35. ** formatting. A few functions were ANSIfied to make
  36. ** the program strictly C89-conforming.
  37. */
  38. #define VERSION "0.1.01"
  39. /* RAH Re-spacing, and examining code - making comments 7-june-2006
  40. **
  41. **
  42. */
  43. #include <time.h>
  44. #include <stdio.h>
  45. #include <ctype.h>
  46. #include <string.h>
  47. #include <stdlib.h>
  48. #include <math.h>
  49. #include <limits.h>
  50. #define TRUE 1
  51. #define FALSE 0
  52. #define PUT 1
  53. #define GET 0
  54. /* AIS #define STEPLIMIT 999*/
  55. /* AIS #define STACKLIMIT 30*/
  56. /* AIS #define ARRAYELEMENTS 999*/
  57. #define LISTFORMAT " %07ld%s"
  58. #define PUT 1
  59. #define GET 0
  60. #define CMDPROMPT ">:"
  61. #define NUMPROMPT ""
  62. /* This macro by AIS. It uses arradjust (defined below) to ensure that a
  63. dynamic array has enough elements to store a value in musthave, or to
  64. read a value from musthave. It does not zero any new data created. */
  65. #define ARRADJUST(a,musthave) a = arradjust(a, sizeof *a, musthave, &size##a);
  66. typedef struct statement
  67. {
  68. long lino;
  69. char text[80];
  70. } STATENODE;
  71. /* Global Variables */
  72. /* AIS: I changed some indexes from int to size_t, to allow as much
  73. dynamic memory to be allocated as possible. laststep was changed
  74. to long (the numeric type used by the program). */
  75. long varz[27]; /* Variables */
  76. /*long ustack[STACKLIMIT]; AIS /+ $ stack */
  77. /*long darray[ARRAYELEMENTS]; AIS /+ User Array */
  78. size_t ustackindex; /* index to free stack item */
  79. /*long compstack[STACKLIMIT]; AIS /+ computational stack */
  80. size_t compstackindex; /* index to free stack item */
  81. /*STATENODE progmem[STEPLIMIT]; AIS /+ Program memory */
  82. long laststep; /* first free step */
  83. char numberformat[20]; /* Number printout format */
  84. /* Dynamic global variables (this section by AIS) */
  85. /* These are explicitly initialized to 0, to mark their deallocated
  86. status. This ought to happen anyway, but some compilers are buggy
  87. in this regard.
  88. (The convention used in this program is that used by realloc; any
  89. dangling pointers should immediately be replaced by null pointers,
  90. and a null pointer means that no memory is allocated for that
  91. particular job.) */
  92. long *ustack = 0;
  93. long *darray = 0;
  94. long *compstack = 0;
  95. STATENODE *progmem = 0;
  96. size_t sizeustack = 0;
  97. size_t sizedarray = 0;
  98. size_t sizecompstack = 0;
  99. size_t sizeprogmem = 0;
  100. /* function prototypes */
  101. void setup(void); /* setup system */
  102. void cleanupatexit(void); /* AIS: cleanup system */
  103. void *arradjust(void *array, size_t elesize,
  104. size_t musthaveele, size_t * arrsize);
  105. /* AIS: Ensures an
  106. * element is
  107. * addressable */
  108. void addprogramstep(long lino, char text[80]);
  109. void listprogram(void);
  110. void loadprogram(char filename[20]);
  111. void saveprogram(char filename[20]);
  112. void execprogram(void);
  113. long cpop(void); /* Pop compstack */
  114. long spop(void); /* Pop storage stack */
  115. void cpush(long in); /* Push comp stack */
  116. void spush(long in); /* Push storage stack */
  117. long inputnumber(void);
  118. int main(int argc, char *argv[]) {
  119. /* AIS: Changed some int to size_t, changed comments for clarity */
  120. char instring[80]; /* input buffer */
  121. char text[80]; /* Parsed input statement w/o line number */
  122. long lino; /* Parsed line number */
  123. char c; /* character temporary */
  124. int going; /* flag is interpreter still going else exit */
  125. size_t place; /* index used while inputing a line */
  126. int i, j; /* General counter and array pointer */
  127. int before; /* flag, before/after line number */
  128. atexit(cleanupatexit); /* AIS: to ensure memory is freed */
  129. /*
  130. ** See if we are running executive mode Vs Interactive mode.
  131. */
  132. if (argc > 1) {
  133. setup();
  134. loadprogram(argv[1]);
  135. execprogram();
  136. exit(EXIT_FAILURE); /* Always?? What if the program completes (.) */
  137. }
  138. printf("\n\nTiny -- Interactive Mode\n\n");
  139. printf("Version :%s\n",VERSION);
  140. printf("Tiny is provided under the \nGNU General Public License \n");
  141. printf("See the file COPYING for details\n\n");
  142. setup();
  143. going = TRUE;
  144. do {
  145. /*
  146. ** Read and store lines. This first part reads a line charactor by
  147. ** charactor, breaks it into line number and line. Then
  148. ** addprogramstep() is used to place the line into the program memory.
  149. ** Commands are detected.
  150. */
  151. /* clear input buffer */
  152. for (i = 0; i < 80; i++) {
  153. instring[i] = '\0';
  154. }
  155. /* read input a string at a time */
  156. place = 0;
  157. /* print prompt */
  158. printf(CMDPROMPT);
  159. /* grab charactors until end of line or line too long */
  160. do {
  161. c = fgetc(stdin);
  162. instring[place] = c;
  163. place = place + 1;
  164. if (place > 80) {
  165. printf("\n\n-- Line too long \n");
  166. }
  167. } while (c != '\0' && c != '\n' && place < 80);
  168. /* detect and execute a command */
  169. if (instring[0] == '#') {
  170. /* bye (exit interpreter ) */
  171. if (tolower(instring[1]) == 'b') {
  172. going = FALSE;
  173. printf("\n\n-- End of Session \n");
  174. }
  175. /* run program #r */
  176. if (tolower(instring[1]) == 'r') {
  177. execprogram();
  178. }
  179. /* #l list program */
  180. if (tolower(instring[1]) == 'l') {
  181. listprogram();
  182. }
  183. /* #s filename Save */
  184. if (tolower(instring[1] == 's')) {
  185. /*
  186. ** discard '#s' and copy filename into text[]
  187. ** todo- need to actually parse out multiple spaces
  188. */
  189. i = 0;
  190. j = 0;
  191. before = FALSE;
  192. while (i < strlen(instring)) {
  193. if (instring[i] == ' ') {
  194. before = TRUE;
  195. /* skip the space */
  196. i++;
  197. }
  198. if (before) {
  199. /* AIS: Added test for period, a common filename character. */
  200. if (isalnum(instring[i]) || instring[i] == '.') {
  201. text[j] = instring[i];
  202. j++;
  203. text[j] = '\0';
  204. } else {
  205. text[j] = '\0'; /* AIS */
  206. }
  207. }
  208. i++;
  209. }
  210. saveprogram(text);
  211. }
  212. /* #n new, Clear program */
  213. if (tolower(instring[1] == 'n')) {
  214. setup();
  215. }
  216. /* #o filename old program (load the program) */
  217. if (tolower(instring[1]) == 'o') {
  218. /* discard '#o' and copy filename into text[] */
  219. i = 0;
  220. j = 0;
  221. before = FALSE;
  222. while (i < strlen(instring)) {
  223. if (instring[i] == ' ') { /* looking for end of name */
  224. before = TRUE;
  225. /* skip the space */
  226. i++;
  227. }
  228. if (before) {
  229. if (isalnum(instring[i])) {
  230. text[j] = instring[i]; /* move a char from input to name */
  231. j++; /* next space in name */
  232. text[j] = '\0'; /* ensure string ends in null */
  233. }
  234. }
  235. i++;
  236. }
  237. loadprogram(text);
  238. }
  239. }
  240. /* Perhaps it's a statement to store */
  241. if (isdigit(instring[0])) {
  242. /* separate statement into lino and text */
  243. lino = 0;
  244. j = 0;
  245. before = TRUE;
  246. for (i = 0; i <= strlen(instring); i++) {
  247. /* locate break after line number */
  248. if (!isdigit(instring[i])) {
  249. before = FALSE;
  250. }
  251. /* if still line number */
  252. if (before) {
  253. /* collect each digit of line number */
  254. lino = lino * 10 + (instring[i] - '0');
  255. } else {
  256. /* else collect text from rest of string */
  257. text[j] = instring[i];
  258. j = j + 1;
  259. }
  260. }
  261. text[j] = '\0'; /* ensure an end of line sentinel */
  262. /* store line in program structure here... */
  263. addprogramstep(lino, text);
  264. printf(LISTFORMAT, lino, text); /* echo program step */
  265. }
  266. } while (going);
  267. return 0;
  268. }
  269. void setup(void) {
  270. int i;
  271. /*
  272. ** initialize all 26 variables.
  273. */
  274. for (i = 0; i < 27; i++) {
  275. varz[i] = 0;
  276. }
  277. /* AIS: initialize dynamic arrays (by realloc to 0) */
  278. ustack = realloc(ustack, 0);
  279. sizeustack = 0;
  280. darray = realloc(darray, 0);
  281. sizedarray = 0;
  282. compstack = realloc(compstack, 0);
  283. sizecompstack = 0;
  284. progmem = realloc(progmem, 0);
  285. sizeprogmem = 0;
  286. /* initialize number format */
  287. strcpy(numberformat, "%ld");
  288. }
  289. /* AIS: Atexit cleanup procedure. */
  290. void cleanupatexit(void) {
  291. /* Free memory and zero the pointers. */
  292. ustack = realloc(ustack, 0);
  293. sizeustack = 0;
  294. darray = realloc(darray, 0);
  295. sizedarray = 0;
  296. compstack = realloc(compstack, 0);
  297. sizecompstack = 0;
  298. progmem = realloc(progmem, 0);
  299. sizeprogmem = 0;
  300. }
  301. /* AIS: Expand an array if needed. */
  302. void *arradjust(void *a, size_t elesize, size_t musthave, size_t * arrsize) {
  303. void *temp;
  304. if (*arrsize > musthave) {
  305. return a; /* Array is already big enough */
  306. }
  307. /*
  308. * Determine new arrsize. Algorithm: Add 4 to arrsize if arrsize < 32, to
  309. * save memory if only a few elements are used; Double arrsize if arrsize *
  310. * elesize < SIZE_MAX/3, to save time when large amounts of data are used;
  311. * Add 1024 to arrsize otherwise, to prevent overwrapping size_t.
  312. */
  313. if (*arrsize < 32)
  314. *arrsize += 4;
  315. #ifdef SIZE_MAX
  316. else if (*arrsize * elesize < SIZE_MAX / 3)
  317. *arrsize *= 2;
  318. #else
  319. else if (*arrsize * elesize < ULONG_MAX / 3)
  320. *arrsize *= 2;
  321. #endif
  322. else
  323. *arrsize += 1024;
  324. temp = realloc(a, *arrsize * elesize);
  325. if (!temp) {
  326. printf("Tiny-- Out of memory\n"); /* This resembles some of the other
  327. * error messages */
  328. free(a);
  329. a = 0;
  330. exit(EXIT_FAILURE);
  331. }
  332. a = temp;
  333. return a;
  334. }
  335. /* This procedure adds a line to the program */
  336. void addprogramstep(long lino, char text[80])
  337. {
  338. ARRADJUST(progmem, laststep); /* AIS */
  339. progmem[laststep].lino = lino;
  340. strcpy(progmem[laststep].text, text);
  341. laststep++;
  342. }
  343. /* This function commented out as it is unused. It has not been
  344. converted to use dynamic memory. (AIS)
  345. void NEWaddprogramstep(long lino, char text[80]) {
  346. int i;
  347. if (strlen(text) == 0) {
  348. /+ find and delete lino +/
  349. } else {
  350. /+ Search forward +/
  351. i=0;
  352. while (lino < progmem[i].lino ) i++;
  353. if (progmem[i].lino == lino) {
  354. /+
  355. ++ Replace this line (lino is already correct, just copy in
  356. ++ the new text.
  357. +/
  358. strcpy(progmem[i].text, text);
  359. } else {
  360. /+ Insert this line here +/
  361. }
  362. }
  363. }
  364. */
  365. void listprogram(void)
  366. {
  367. int i;
  368. for (i = 0; i < laststep; i++)
  369. {
  370. printf(LISTFORMAT, progmem[i].lino, progmem[i].text);
  371. }
  372. printf("\n");
  373. }
  374. void loadprogram(char filename[20]) {
  375. FILE *fp;
  376. char instring[80];
  377. char text[80];
  378. int before;
  379. int i, j;
  380. long lino;
  381. char *eflag;
  382. fp = fopen(filename, "r");
  383. if (fp == NULL)
  384. {
  385. printf("Tiny--Can't open file [%s] \n", filename);
  386. } else
  387. {
  388. do
  389. {
  390. eflag = fgets(instring, 80, fp);
  391. if (eflag != NULL)
  392. {
  393. /* separate statement into lino and text */
  394. lino = 0;
  395. j = 0;
  396. before = TRUE;
  397. for (i = 0; i <= strlen(instring); i++) {
  398. /* locate break after line number */
  399. if (!isdigit(instring[i])) {
  400. before = FALSE;
  401. }
  402. /* if still line number */
  403. if (before) {
  404. /* collect each digit of line number */
  405. lino = lino * 10 + (instring[i] - '0');
  406. } else {
  407. /* else collect text from rest of string */
  408. text[j] = instring[i];
  409. j++;
  410. }
  411. }
  412. text[j] = '\0'; /* ensure an end of line sentinel */
  413. addprogramstep(lino, text);
  414. /* printf(LISTFORMAT,lino,text); */
  415. }
  416. } while (eflag != NULL);
  417. fclose(fp);
  418. }
  419. }
  420. /* AIS: Removed illegal trailing semicolons on these functions. */
  421. long cpop(void) {
  422. compstackindex--;
  423. return compstack[compstackindex];
  424. }
  425. long spop(void) {
  426. ustackindex--;
  427. return ustack[ustackindex];
  428. }
  429. void cpush(long in) {
  430. ARRADJUST(compstack, compstackindex); /* AIS */
  431. compstack[compstackindex] = in;
  432. compstackindex++;
  433. }
  434. void spush(long in) {
  435. ARRADJUST(ustack, ustackindex); /* AIS */
  436. ustack[ustackindex] = in;
  437. ustackindex++;
  438. }
  439. /*
  440. ** execprogram
  441. **
  442. ** This executes the program that is currently loaded.
  443. **
  444. */
  445. void execprogram(void) {
  446. long x, y; /* Temporary */
  447. long exlino; /* effective lino (@ register) */
  448. long thenumber; /* Used to collect numeric constants */
  449. char xtext[80]; /* Program text being interpreted */
  450. char xchar; /* actual char being interpreted */
  451. char xstr[2]; /* when we need a string xchar instead */
  452. int i; /* loop indexes */
  453. int running; /* flag - running */
  454. int progmemstep; /* index into progmem */
  455. int putget; /* put get flag */
  456. int indirect; /* indirect flag (array?) */
  457. int numbuild; /* building a number */
  458. int StringPrint; /* Printing */
  459. /* int AIS: unused BackSlash; /+ Prev Char was a backslash */
  460. /* int AIS: unused Parencomment; /+ Paren comment level */
  461. /* int AIS: unused Poundcomment; /+ Pound Comment */
  462. long arrayindex; /* Index into user array */
  463. int gatherformat; /* Flag used while reading format strings */
  464. /* setup */
  465. putget = GET;
  466. numbuild = FALSE;
  467. StringPrint = FALSE;
  468. /* BackSlash = FALSE; AIS: Unused */
  469. indirect = FALSE;
  470. /* Parencomment = 0; AIS: Unused /+ not inside parens */
  471. /* Poundcomment = FALSE; AIS: Unused /+ No Poundsign comment yet */
  472. gatherformat = FALSE;
  473. /* Get first Line Number */
  474. progmemstep = 0;
  475. exlino = progmem[progmemstep].lino;
  476. running = TRUE;
  477. do {
  478. /* locate line from @ */
  479. progmemstep = 0;
  480. while (progmem[progmemstep].lino != exlino) {
  481. progmemstep++;
  482. /* if past lastline then error message stop */
  483. if (progmemstep > laststep) {
  484. printf("Tiny-- Attempt to jump to %ld, line not found\n", exlino);
  485. running = FALSE;
  486. break;
  487. }
  488. }
  489. /* fetch line */
  490. strcpy(xtext, progmem[progmemstep].text);
  491. if (strlen(xtext) == 0) {
  492. printf("Tiny-- Execute past end of program\n");
  493. running = FALSE;
  494. }
  495. /* set @ to line number of next line */
  496. exlino = progmem[progmemstep + 1].lino;
  497. /* interpret line */
  498. for (i = 0; i < strlen(xtext); i++) {
  499. xchar = xtext[i];
  500. if (xchar == '#') {
  501. break;
  502. }
  503. if (StringPrint)
  504. {
  505. if (xchar == '\\')
  506. {
  507. i++;
  508. xchar = xtext[i];
  509. switch (xchar) {
  510. case 'n':
  511. printf("\n");
  512. break;
  513. case 't':
  514. printf("\t");
  515. break;
  516. case '\\':
  517. printf("\\");
  518. break;
  519. case 'e':
  520. printf("\033");
  521. break;
  522. case '"':
  523. printf("\"");
  524. break;
  525. case '\'':
  526. printf("'");
  527. break;
  528. default:
  529. printf("\n**backslash what? %c\n", xchar);
  530. }
  531. } else {
  532. if (xchar == '"')
  533. {
  534. StringPrint = FALSE;
  535. } else {
  536. printf("%c", xchar);
  537. }
  538. }
  539. } else {
  540. /*
  541. ** Gatherformat, this section handles the format string * looking
  542. ** for a single qoute and gathering everythg beween * the first
  543. ** single qoute and the second.
  544. */
  545. if (gatherformat) {
  546. if (xchar == '\'')
  547. {
  548. xchar = '\0';
  549. gatherformat = FALSE;
  550. } else {
  551. xstr[0] = xchar;
  552. xstr[1] = '\0';
  553. strcat(numberformat, xstr);
  554. xchar = '\0';
  555. }
  556. }
  557. if (xchar == '\'') {
  558. /*
  559. ** When first we notice a single qoute, clear the numberformat
  560. ** and begin to gather new characters in numberformat.
  561. */
  562. gatherformat = TRUE;
  563. strcpy(numberformat, "\0");
  564. }
  565. /* user Array usage */
  566. if (xchar == '(') {
  567. indirect = TRUE;
  568. }
  569. if (xchar == ')') {
  570. indirect = FALSE;
  571. }
  572. /* period is the "stop program " */
  573. if (xchar == '.') {
  574. running = FALSE;
  575. break;
  576. }
  577. if (isdigit(xchar)) {
  578. if (numbuild) {
  579. /*
  580. ** should probably try to detect numeric constant that
  581. ** is too big here.
  582. */
  583. thenumber = (10 * thenumber) + (xchar - '0');
  584. } else {
  585. numbuild = TRUE;
  586. thenumber = xchar - '0';
  587. }
  588. }
  589. /* first non digit after a number */
  590. if (!isdigit(xchar)) {
  591. if (numbuild) {
  592. cpush(thenumber);
  593. numbuild = FALSE;
  594. }
  595. }
  596. /* Get/Put Variables */
  597. xchar = tolower(xchar);
  598. if (xchar <= 'z' && 'a' <= xchar) {
  599. if (putget == GET) {
  600. if (indirect) {
  601. arrayindex = varz[xchar - 'a'];
  602. if ( arrayindex >= 0) {
  603. ARRADJUST(darray, arrayindex); /* AIS */
  604. cpush(darray[arrayindex]);
  605. } else {
  606. printf("TINY %ld -- Recall from Array out of range %ld \n",
  607. exlino, arrayindex);
  608. }
  609. } else {
  610. cpush(varz[xchar - 'a']);
  611. }
  612. } else {
  613. if (indirect) {
  614. arrayindex = varz[xchar - 'a'];
  615. if ( arrayindex >= 0) {
  616. ARRADJUST(darray, arrayindex); /* AIS */
  617. darray[arrayindex] = cpop();
  618. cpush(darray[arrayindex]);
  619. } else {
  620. printf("TINY %ld -- Store to Arry out of range %ld \n",
  621. exlino, arrayindex);
  622. }
  623. } else {
  624. varz[xchar - 'a'] = cpop();
  625. cpush(varz[xchar - 'a']);
  626. }
  627. }
  628. }
  629. switch (xchar) {
  630. case '[':
  631. compstackindex = 0;
  632. putget = GET;
  633. break;
  634. case ']':
  635. putget = PUT;
  636. break;
  637. case '"':
  638. StringPrint = TRUE;
  639. break;
  640. case '+':
  641. cpush(cpop() + cpop());
  642. break;
  643. case '*':
  644. cpush(cpop() * cpop());
  645. break;
  646. case '!':
  647. cpush(!cpop());
  648. break;
  649. case '%':
  650. x = cpop();
  651. y = cpop();
  652. cpush(y % x);
  653. break;
  654. case '^':
  655. x = cpop();
  656. y = cpop();
  657. cpush((long) pow((double) y, (double) x));
  658. break;
  659. case '-':
  660. x = cpop();
  661. y = cpop();
  662. cpush(y - x);
  663. break;
  664. case '/':
  665. x = cpop();
  666. y = cpop();
  667. if (x == 0) {
  668. printf("Tiny -- %ld div by zero! Black hole forming!\n", exlino);
  669. } else {
  670. cpush(y / x);
  671. }
  672. break;
  673. case '<':
  674. x = cpop();
  675. y = cpop();
  676. cpush(y < x);
  677. break;
  678. case '>':
  679. x = cpop();
  680. y = cpop();
  681. cpush(y > x);
  682. break;
  683. case '=':
  684. cpush(cpop() == cpop());
  685. break;
  686. case '&':
  687. cpush(cpop() && cpop());
  688. break;
  689. case '|':
  690. cpush(cpop() || cpop());
  691. break;
  692. /* Special Variables */
  693. case '~':
  694. if (putget == GET) {
  695. cpush(labs( rand()));
  696. } else {
  697. x = cpop();
  698. cpush(x);
  699. if (x == 0) {
  700. x = (int) time(NULL);
  701. }
  702. srand(x);
  703. }
  704. break;
  705. case '?':
  706. if (putget == GET) {
  707. printf("%s", NUMPROMPT); /* AIS: Satisfying a reasonable
  708. * compiler warning */
  709. x = inputnumber();
  710. cpush(x);
  711. } else {
  712. x = cpop();
  713. cpush(x);
  714. printf(numberformat, x);
  715. }
  716. break;
  717. case '@':
  718. if (putget == GET) {
  719. cpush(exlino);
  720. } else {
  721. x = cpop();
  722. cpush(x);
  723. if (x != 0) {
  724. exlino = x;
  725. }
  726. }
  727. break;
  728. case '$':
  729. if (putget == GET) {
  730. cpush(spop());
  731. } else {
  732. x = cpop();
  733. cpush(x);
  734. spush(x);
  735. }
  736. break;
  737. }
  738. }
  739. }
  740. if ((compstackindex + 1) == 0) {
  741. /*
  742. ** AIS: Changed condition to allow
  743. ** for unsigned compstackindex
  744. */
  745. printf("*** Tiny -- Comp Stack underflow \n");
  746. running = FALSE;
  747. }
  748. } while (running); /* execute do loop */
  749. } /* execprogram */
  750. long inputnumber(void) {
  751. #define CR '\n' /* AIS: ANSIfication */
  752. #define BS '\b' /* AIS: ANSIfication */
  753. long val;
  754. char c;
  755. int nflag;
  756. val = 0;
  757. nflag = FALSE;
  758. do {
  759. c = getchar();
  760. if (c != CR) {
  761. if (c == BS) {
  762. val = val / 10;
  763. }
  764. if (c == '-') {
  765. nflag = TRUE;
  766. }
  767. if (c <= '9' && c >= '0') {
  768. val = (val * 10) + (c - '0');
  769. }
  770. }
  771. } while (c != CR);
  772. if (nflag) {
  773. val = 0 - val;
  774. }
  775. return val;
  776. }
  777. void saveprogram(char filename[20]) {
  778. FILE *fp;
  779. long i;
  780. fp = fopen(filename, "w");
  781. /* AIS: Check for program not openable */
  782. if (!fp) {
  783. perror(filename); /* rah why not print a tiny style error message */
  784. return;
  785. }
  786. for (i = 0; i < laststep; i++) {
  787. fprintf(fp, LISTFORMAT, progmem[i].lino, progmem[i].text);
  788. }
  789. fclose(fp);
  790. /* AIS: File Saved message */
  791. printf("Tiny-- File saved to %s.\n", filename);
  792. }