home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / calc / part19 < prev    next >
Encoding:
Text File  |  1992-05-09  |  38.3 KB  |  1,714 lines

  1. Newsgroups: comp.sources.unix
  2. From: dbell@pdact.pd.necisa.oz.au (David I. Bell)
  3. Subject: v26i045: CALC - An arbitrary precision C-like calculator, Part19/21
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: dbell@pdact.pd.necisa.oz.au (David I. Bell)
  8. Posting-Number: Volume 26, Issue 45
  9. Archive-Name: calc/part19
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 19 (of 21)."
  18. # Contents:  codegen.c
  19. # Wrapped by dbell@elm on Tue Feb 25 15:21:17 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'codegen.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'codegen.c'\"
  23. else
  24. echo shar: Extracting \"'codegen.c'\" \(35857 characters\)
  25. sed "s/^X//" >'codegen.c' <<'END_OF_FILE'
  26. X/*
  27. X * Copyright (c) 1992 David I. Bell
  28. X * Permission is granted to use, distribute, or modify this source,
  29. X * provided that this copyright notice remains intact.
  30. X *
  31. X * Module to generate opcodes from the input tokens.
  32. X */
  33. X
  34. X#include "calc.h"
  35. X#include "token.h"
  36. X#include "symbol.h"
  37. X#include "label.h"
  38. X#include "opcodes.h"
  39. X#include "string.h"
  40. X#include "func.h"
  41. X#include "config.h"
  42. X
  43. X
  44. XFUNC *curfunc;
  45. X
  46. Xstatic BOOL getfilename(), getid();
  47. Xstatic void getshowcommand(), getfunction(), getbody(), getdeclarations();
  48. Xstatic void getstatement(), getobjstatement(), getobjvars();
  49. Xstatic void getmatstatement(), getsimplebody();
  50. Xstatic void getcondition(), getmatargs(), getelement(), checksymbol();
  51. Xstatic void getcallargs();
  52. Xstatic int getexprlist(), getassignment(), getaltcond(), getorcond();
  53. Xstatic int getandcond(), getrelation(), getsum(), getproduct();
  54. Xstatic int getorexpr(), getandexpr(), getshiftexpr(), getterm();
  55. Xstatic int getidexpr();
  56. X
  57. X/*
  58. X * Read all the commands from an input file.
  59. X * These are either declarations, or else are commands to execute now.
  60. X * In general, commands are terminated by newlines or semicolons.
  61. X * Exceptions are function definitions and escaped newlines.
  62. X * Commands are read and executed until the end of file.
  63. X */
  64. Xvoid
  65. Xgetcommands()
  66. X{
  67. X    char name[PATHSIZE+1];    /* program name */
  68. X
  69. X    for (;;) {
  70. X        tokenmode(TM_NEWLINES);
  71. X        switch (gettoken()) {
  72. X
  73. X        case T_DEFINE:
  74. X            getfunction();
  75. X            break;
  76. X
  77. X        case T_EOF:
  78. X            return;
  79. X
  80. X        case T_HELP:
  81. X            if (!getfilename(name, FALSE)) {
  82. X                strcpy(name, DEFAULTCALCHELP);
  83. X            }
  84. X            givehelp(name);
  85. X            break;
  86. X
  87. X        case T_READ:
  88. X            if (!getfilename(name, TRUE))
  89. X                break;
  90. X            if (opensearchfile(name, calcpath, CALCEXT) < 0) {
  91. X                scanerror(T_NULL, "Cannot open \"%s\"\n", name);
  92. X                break;
  93. X            }
  94. X            getcommands();
  95. X            break;
  96. X
  97. X        case T_WRITE:
  98. X            if (!getfilename(name, TRUE))
  99. X                break;
  100. X            if (writeglobals(name))
  101. X                scanerror(T_NULL, "Error writing \"%s\"\n", name);
  102. X            break;
  103. X
  104. X        case T_SHOW:
  105. X            rescantoken();
  106. X            getshowcommand();
  107. X            break;
  108. X
  109. X        case T_NEWLINE:
  110. X        case T_SEMICOLON:
  111. X            break;
  112. X
  113. X        default:
  114. X            rescantoken();
  115. X            initstack();
  116. X            if (evaluate(FALSE))
  117. X                updateoldvalue(curfunc);
  118. X        }
  119. X    }
  120. X}
  121. X
  122. X
  123. X/*
  124. X * Evaluate a line of statements.
  125. X * This is done by treating the current line as a function body,
  126. X * compiling it, and then executing it.  Returns TRUE if the line
  127. X * successfully compiled and executed.  The last expression result
  128. X * is saved in the f_savedvalue element of the current function.
  129. X * The nestflag variable should be FALSE for the outermost evaluation
  130. X * level, and TRUE for all other calls (such as the 'eval' function).
  131. X * The function name begins with an asterisk to indicate specialness.
  132. X */
  133. XBOOL
  134. Xevaluate(nestflag)
  135. X    BOOL nestflag;        /* TRUE if this is a nested evaluation */
  136. X{
  137. X    char *funcname;
  138. X    BOOL gotstatement;
  139. X
  140. X    funcname = (nestflag ? "**" : "*");
  141. X    beginfunc(funcname, nestflag);
  142. X    gotstatement = FALSE;
  143. X    for (;;) {
  144. X        switch (gettoken()) {
  145. X            case T_SEMICOLON:
  146. X                break;
  147. X
  148. X            case T_EOF:
  149. X                rescantoken();
  150. X                goto done;
  151. X
  152. X            case T_NEWLINE:
  153. X                goto done;
  154. X
  155. X            case T_GLOBAL:
  156. X            case T_LOCAL:
  157. X                if (gotstatement) {
  158. X                    scanerror(T_SEMICOLON, "Declarations must be used before code");
  159. X                    return FALSE;
  160. X                }
  161. X                rescantoken();
  162. X                getdeclarations();
  163. X                break;
  164. X
  165. X            default:
  166. X                rescantoken();
  167. X                getstatement(NULL, NULL, NULL, NULL);
  168. X                gotstatement = TRUE;
  169. X        }
  170. X    }
  171. X
  172. Xdone:
  173. X    addop(OP_UNDEF);
  174. X    addop(OP_RETURN);
  175. X    checklabels();
  176. X    if (errorcount)
  177. X        return FALSE;
  178. X    calculate(curfunc, 0);
  179. X    return TRUE;
  180. X}
  181. X
  182. X
  183. X/*
  184. X * Get a function declaration.
  185. X * func = name '(' '' | name [ ',' name] ... ')' simplebody
  186. X *    | name '(' '' | name [ ',' name] ... ')' body.
  187. X */
  188. Xstatic void
  189. Xgetfunction()
  190. X{
  191. X    char *name;        /* parameter name */
  192. X    int type;        /* type of token read */
  193. X
  194. X    tokenmode(TM_DEFAULT);
  195. X    if (gettoken() != T_SYMBOL) {
  196. X        scanerror(T_NULL, "Function name expected");
  197. X        return;
  198. X    }
  199. X    beginfunc(tokenstring(), FALSE);
  200. X    if (gettoken() != T_LEFTPAREN) {
  201. X        scanerror(T_SEMICOLON, "Left parenthesis expected for function");
  202. X        return;
  203. X    }
  204. X    for (;;) {
  205. X        type = gettoken();
  206. X        if (type == T_RIGHTPAREN)
  207. X            break;
  208. X        if (type != T_SYMBOL) {
  209. X            scanerror(T_COMMA, "Bad function definition");
  210. X            return;
  211. X        }
  212. X        name = tokenstring();
  213. X        switch (symboltype(name)) {
  214. X            case SYM_UNDEFINED:
  215. X            case SYM_GLOBAL:
  216. X                (void) addparam(name);
  217. X                break;
  218. X            default:
  219. X                scanerror(T_NULL, "Parameter \"%s\" is already defined", name);
  220. X        }
  221. X        type = gettoken();
  222. X        if (type == T_RIGHTPAREN)
  223. X            break;
  224. X        if (type != T_COMMA) {
  225. X            scanerror(T_COMMA, "Bad function definition");
  226. X            return;
  227. X        }
  228. X    }
  229. X    switch (gettoken()) {
  230. X        case T_ASSIGN:
  231. X            rescantoken();
  232. X            getsimplebody();
  233. X            break;
  234. X        case T_LEFTBRACE:
  235. X            rescantoken();
  236. X            getbody(NULL, NULL, NULL, NULL, TRUE);
  237. X            break;
  238. X        default:
  239. X            scanerror(T_NULL,
  240. X                "Left brace or equals sign expected for function");
  241. X            return;
  242. X    }
  243. X    addop(OP_UNDEF);
  244. X    addop(OP_RETURN);
  245. X    endfunc();
  246. X}
  247. X
  248. X
  249. X/*
  250. X * Get a simple assignment style body for a function declaration.
  251. X * simplebody = '=' assignment '\n'.
  252. X */
  253. Xstatic void
  254. Xgetsimplebody()
  255. X{
  256. X    if (gettoken() != T_ASSIGN) {
  257. X        scanerror(T_SEMICOLON, "Missing equals for simple function body");
  258. X        return;
  259. X    }
  260. X    tokenmode(TM_NEWLINES);
  261. X    (void) getexprlist();
  262. X    addop(OP_RETURN);
  263. X    if (gettoken() != T_SEMICOLON)
  264. X        rescantoken();
  265. X    if (gettoken() != T_NEWLINE)
  266. X        scanerror(T_NULL, "Illegal function definition");
  267. X}
  268. X
  269. X
  270. X/*
  271. X * Get the body of a function, or a subbody of a function.
  272. X * body = '{' [ declarations ] ... [ statement ] ... '}'
  273. X *    | [ declarations ] ... [statement ] ... '\n'
  274. X */
  275. Xstatic void
  276. Xgetbody(contlabel, breaklabel, nextcaselabel, defaultlabel, toplevel)
  277. X    LABEL *contlabel, *breaklabel, *nextcaselabel, *defaultlabel;
  278. X    BOOL toplevel;
  279. X{
  280. X    BOOL gotstatement;    /* TRUE if seen a real statement yet */
  281. X
  282. X    if (gettoken() != T_LEFTBRACE) {
  283. X        scanerror(T_SEMICOLON, "Missing left brace for function body");
  284. X        return;
  285. X    }
  286. X    gotstatement = FALSE;
  287. X    for (;;) {
  288. X        switch (gettoken()) {
  289. X        case T_RIGHTBRACE:
  290. X            return;
  291. X
  292. X        case T_GLOBAL:
  293. X        case T_LOCAL:
  294. X            if (!toplevel) {
  295. X                scanerror(T_SEMICOLON, "Declarations must be at the top of the function");
  296. X                return;
  297. X            }
  298. X            if (gotstatement) {
  299. X                scanerror(T_SEMICOLON, "Declarations must be used before code");
  300. X                return;
  301. X            }
  302. X            rescantoken();
  303. X            getdeclarations();
  304. X            break;
  305. X
  306. X        default:
  307. X            rescantoken();
  308. X            getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
  309. X            gotstatement = TRUE;
  310. X        }
  311. X    }
  312. X}
  313. X
  314. X
  315. X/*
  316. X * Get a line of local or global variable declarations.
  317. X * declarations = { LOCAL | GLOBAL } name [ ',' name ] ... ';'.
  318. X */
  319. Xstatic void
  320. Xgetdeclarations()
  321. X{
  322. X    int type;        /* type of declaration */
  323. X    char *name;        /* name of symbol seen */
  324. X
  325. X    switch (gettoken()) {
  326. X        case T_LOCAL:
  327. X            type = SYM_LOCAL;
  328. X            break;
  329. X        case T_GLOBAL:
  330. X            type = SYM_GLOBAL;
  331. X            break;
  332. X        default:
  333. X            rescantoken();
  334. X            return;
  335. X    }
  336. X    for (;;) {
  337. X        if (gettoken() != T_SYMBOL) {
  338. X            scanerror(T_SEMICOLON, "Variable name expected for declaration statement");
  339. X            return;
  340. X        }
  341. X        name = tokenstring();
  342. X        switch (symboltype(name)) {
  343. X        case SYM_UNDEFINED:
  344. X        case SYM_GLOBAL:
  345. X            if (type == SYM_LOCAL)
  346. X                (void) addlocal(name);
  347. X            else
  348. X                (void) addglobal(name);
  349. X            break;
  350. X        case SYM_PARAM:
  351. X        case SYM_LOCAL:
  352. X            scanerror(T_NULL, "variable \"%s\" is already defined", name);
  353. X            break;
  354. X        }
  355. X        switch (gettoken()) {
  356. X            case T_COMMA:
  357. X                break;
  358. X            case T_NEWLINE:
  359. X            case T_SEMICOLON:
  360. X                return;
  361. X            default:
  362. X                scanerror(T_SEMICOLON, "Bad syntax in declaration statement");
  363. X                return;
  364. X        }
  365. X    }
  366. X}
  367. X
  368. X
  369. X/*
  370. X * Get a statement.
  371. X * statement = IF condition statement [ELSE statement]
  372. X *    | FOR '(' [assignment] ';' [assignment] ';' [assignment] ')' statement
  373. X *    | WHILE condition statement
  374. X *    | DO statement WHILE condition ';'
  375. X *    | SWITCH condition '{' [caseclause] ... '}'
  376. X *    | CONTINUE ';'
  377. X *    | BREAK ';'
  378. X *    | RETURN assignment ';'
  379. X *    | GOTO label ';'
  380. X *    | MAT name '[' value [ ':' value ] [',' value [ ':' value ] ] ']' ';'
  381. X *    | OBJ type '{' arg [ ',' arg ] ... '}' ] ';'
  382. X *    | OBJ type name [ ',' name ] ';'
  383. X *    | PRINT assignment [, assignment ] ... ';'
  384. X *    | QUIT [ string ] ';'
  385. X *    | SHOW item ';'
  386. X *    | body
  387. X *    | assignment ';'
  388. X *    | label ':' statement
  389. X *    | ';'.
  390. X */
  391. Xstatic void
  392. Xgetstatement(contlabel, breaklabel, nextcaselabel, defaultlabel)
  393. X    LABEL *contlabel;    /* label for continue statement */
  394. X    LABEL *breaklabel;    /* label for break statement */
  395. X    LABEL *nextcaselabel;    /* label for next case statement */
  396. X    LABEL *defaultlabel;    /* label for default case */
  397. X{
  398. X    LABEL label1, label2, label3, label4;    /* locations for jumps */
  399. X    int type;
  400. X    BOOL printeol;
  401. X
  402. X    addopindex(OP_DEBUG, linenumber());
  403. X    switch (gettoken()) {
  404. X    case T_NEWLINE:
  405. X        rescantoken();
  406. X        return;
  407. X
  408. X    case T_SEMICOLON:
  409. X        return;
  410. X
  411. X    case T_RIGHTBRACE:
  412. X        scanerror(T_NULL, "Extraneous right brace");
  413. X        return;
  414. X
  415. X    case T_CONTINUE:
  416. X        if (contlabel == NULL) {
  417. X            scanerror(T_SEMICOLON, "CONTINUE not within FOR, WHILE, or DO");
  418. X            return;
  419. X        }
  420. X        addoplabel(OP_JUMP, contlabel);
  421. X        break;
  422. X
  423. X    case T_BREAK:
  424. X        if (breaklabel == NULL) {
  425. X            scanerror(T_SEMICOLON, "BREAK not within FOR, WHILE, or DO");
  426. X            return;
  427. X        }
  428. X        addoplabel(OP_JUMP, breaklabel);
  429. X        break;
  430. X
  431. X    case T_GOTO:
  432. X        if (gettoken() != T_SYMBOL) {
  433. X            scanerror(T_SEMICOLON, "Missing label in goto");
  434. X            return;
  435. X        }
  436. X        addop(OP_JUMP);
  437. X        addlabel(tokenstring());
  438. X        break;
  439. X
  440. X    case T_RETURN:
  441. X        switch (gettoken()) {
  442. X            case T_NEWLINE:
  443. X            case T_SEMICOLON:
  444. X                addop(OP_UNDEF);
  445. X                addop(OP_RETURN);
  446. X                return;
  447. X            default:
  448. X                rescantoken();
  449. X                (void) getexprlist();
  450. X                if (curfunc->f_name[0] == '*')
  451. X                    addop(OP_SAVE);
  452. X                addop(OP_RETURN);
  453. X        }
  454. X        break;
  455. X
  456. X    case T_LEFTBRACE:
  457. X        rescantoken();
  458. X        getbody(contlabel, breaklabel, nextcaselabel, defaultlabel, FALSE);
  459. X        return;
  460. X
  461. X    case T_IF:
  462. X        clearlabel(&label1);
  463. X        clearlabel(&label2);
  464. X        getcondition();
  465. X        addoplabel(OP_JUMPEQ, &label1);
  466. X        getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
  467. X        if (gettoken() != T_ELSE) {
  468. X            setlabel(&label1);
  469. X            rescantoken();
  470. X            return;
  471. X        }
  472. X        addoplabel(OP_JUMP, &label2);
  473. X        setlabel(&label1);
  474. X        getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
  475. X        setlabel(&label2);
  476. X        return;
  477. X
  478. X    case T_FOR:    /* for (a; b; c) x */
  479. X        clearlabel(&label1);
  480. X        clearlabel(&label2);
  481. X        clearlabel(&label3);
  482. X        clearlabel(&label4);
  483. X        contlabel = NULL;
  484. X        breaklabel = &label4;
  485. X        if (gettoken() != T_LEFTPAREN) {
  486. X            scanerror(T_SEMICOLON, "Left parenthesis expected");
  487. X            return;
  488. X        }
  489. X        if (gettoken() != T_SEMICOLON) {    /* have 'a' part */
  490. X            rescantoken();
  491. X            (void) getexprlist();
  492. X            addop(OP_POP);
  493. X            if (gettoken() != T_SEMICOLON) {
  494. X                scanerror(T_SEMICOLON, "Missing semicolon");
  495. X                return;
  496. X            }
  497. X        }
  498. X        if (gettoken() != T_SEMICOLON) {    /* have 'b' part */
  499. X            setlabel(&label1);
  500. X            contlabel = &label1;
  501. X            rescantoken();
  502. X            (void) getexprlist();
  503. X            addoplabel(OP_JUMPNE, &label3);
  504. X            addoplabel(OP_JUMP, breaklabel);
  505. X            if (gettoken() != T_SEMICOLON) {
  506. X                scanerror(T_SEMICOLON, "Missing semicolon");
  507. X                return;
  508. X            }
  509. X        }
  510. X        if (gettoken() != T_RIGHTPAREN) {    /* have 'c' part */
  511. X            if (label1.l_offset <= 0)
  512. X                addoplabel(OP_JUMP, &label3);
  513. X            setlabel(&label2);
  514. X            contlabel = &label2;
  515. X            rescantoken();
  516. X            (void) getexprlist();
  517. X            addop(OP_POP);
  518. X            if (label1.l_offset > 0)
  519. X                addoplabel(OP_JUMP, &label1);
  520. X            if (gettoken() != T_RIGHTPAREN) {
  521. X                scanerror(T_SEMICOLON, "Right parenthesis expected");
  522. X                return;
  523. X            }
  524. X        }
  525. X        setlabel(&label3);
  526. X        if (contlabel == NULL)
  527. X            contlabel = &label3;
  528. X        getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
  529. X        addoplabel(OP_JUMP, contlabel);
  530. X        setlabel(breaklabel);
  531. X        return;
  532. X
  533. X    case T_WHILE:
  534. X        contlabel = &label1;
  535. X        breaklabel = &label2;
  536. X        clearlabel(contlabel);
  537. X        clearlabel(breaklabel);
  538. X        setlabel(contlabel);
  539. X        getcondition();
  540. X        addoplabel(OP_JUMPEQ, breaklabel);
  541. X        getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
  542. X        addoplabel(OP_JUMP, contlabel);
  543. X        setlabel(breaklabel);
  544. X        return;
  545. X
  546. X    case T_DO:
  547. X        contlabel = &label1;
  548. X        breaklabel = &label2;
  549. X        clearlabel(contlabel);
  550. X        clearlabel(breaklabel);
  551. X        clearlabel(&label3);
  552. X        setlabel(&label3);
  553. X        getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
  554. X        if (gettoken() != T_WHILE) {
  555. X            scanerror(T_SEMICOLON, "WHILE keyword expected for DO statement");
  556. X            return;
  557. X        }
  558. X        setlabel(contlabel);
  559. X        getcondition();
  560. X        addoplabel(OP_JUMPNE, &label3);
  561. X        setlabel(breaklabel);
  562. X        return;
  563. X
  564. X    case T_SWITCH:
  565. X        breaklabel = &label1;
  566. X        nextcaselabel = &label2;
  567. X        defaultlabel = &label3;
  568. X        clearlabel(breaklabel);
  569. X        clearlabel(nextcaselabel);
  570. X        clearlabel(defaultlabel);
  571. X        getcondition();
  572. X        if (gettoken() != T_LEFTBRACE) {
  573. X            scanerror(T_SEMICOLON, "Missing left brace for switch statement");
  574. X            return;
  575. X        }
  576. X        addoplabel(OP_JUMP, nextcaselabel);
  577. X        rescantoken();
  578. X        getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
  579. X        addoplabel(OP_JUMP, breaklabel);
  580. X        setlabel(nextcaselabel);
  581. X        if (defaultlabel->l_offset > 0)
  582. X            addoplabel(OP_JUMP, defaultlabel);
  583. X        else
  584. X            addop(OP_POP);
  585. X        setlabel(breaklabel);
  586. X        return;
  587. X
  588. X    case T_CASE:
  589. X        if (nextcaselabel == NULL) {
  590. X            scanerror(T_SEMICOLON, "CASE not within SWITCH statement");
  591. X            return;
  592. X        }
  593. X        clearlabel(&label1);
  594. X        addoplabel(OP_JUMP, &label1);
  595. X        setlabel(nextcaselabel);
  596. X        clearlabel(nextcaselabel);
  597. X        (void) getexprlist();
  598. X        if (gettoken() != T_COLON) {
  599. X            scanerror(T_SEMICOLON, "Colon expected after CASE expression");
  600. X            return;
  601. X        }
  602. X        addoplabel(OP_CASEJUMP, nextcaselabel);
  603. X        setlabel(&label1);
  604. X        getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
  605. X        return;
  606. X
  607. X    case T_DEFAULT:
  608. X        if (gettoken() != T_COLON) {
  609. X            scanerror(T_SEMICOLON, "Colon expected after DEFAULT keyword");
  610. X            return;
  611. X        }
  612. X        if (defaultlabel == NULL) {
  613. X            scanerror(T_SEMICOLON, "DEFAULT not within SWITCH statement");
  614. X            return;
  615. X        }
  616. X        if (defaultlabel->l_offset > 0) {
  617. X            scanerror(T_SEMICOLON, "Multiple DEFAULT clauses in SWITCH");
  618. X            return;
  619. X        }
  620. X        clearlabel(&label1);
  621. X        addoplabel(OP_JUMP, &label1);
  622. X        setlabel(defaultlabel);
  623. X        addop(OP_POP);
  624. X        setlabel(&label1);
  625. X        getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
  626. X        return;
  627. X
  628. X    case T_ELSE:
  629. X        scanerror(T_SEMICOLON, "ELSE without preceeding IF");
  630. X        return;
  631. X
  632. X    case T_MAT:
  633. X        getmatstatement();
  634. X        break;
  635. X
  636. X    case T_OBJ:
  637. X        getobjstatement();
  638. X        break;
  639. X
  640. X    case T_PRINT:
  641. X        printeol = TRUE;
  642. X        for (;;) {
  643. X            switch (gettoken()) {
  644. X                case T_RIGHTBRACE:
  645. X                case T_NEWLINE:
  646. X                    rescantoken();
  647. X                    /*FALLTHRU*/
  648. X                case T_SEMICOLON:
  649. X                    if (printeol)
  650. X                        addop(OP_PRINTEOL);
  651. X                    return;
  652. X                case T_COLON:
  653. X                    printeol = FALSE;
  654. X                    break;
  655. X                case T_COMMA:
  656. X                    printeol = TRUE;
  657. X                    addop(OP_PRINTSPACE);
  658. X                    break;
  659. X                case T_STRING:
  660. X                    printeol = TRUE;
  661. X                    addopptr(OP_PRINTSTRING, tokenstring());
  662. X                    break;
  663. X                default:
  664. X                    printeol = TRUE;
  665. X                    rescantoken();
  666. X                    (void) getassignment();
  667. X                    addopindex(OP_PRINT,
  668. X                        (long) PRINT_NORMAL);
  669. X            }
  670. X        }
  671. X        break;
  672. X
  673. X    case T_QUIT:
  674. X        switch (gettoken()) {
  675. X            case T_STRING:
  676. X                addopptr(OP_QUIT, tokenstring());
  677. X                break;
  678. X            default:
  679. X                addopptr(OP_QUIT, NULL);
  680. X                rescantoken();
  681. X        }
  682. X        break;
  683. X
  684. X    case T_SYMBOL:
  685. X        if (nextchar() == ':') {    /****HACK HACK ****/
  686. X            definelabel(tokenstring());
  687. X            getstatement(contlabel, breaklabel, 
  688. X                (LABEL*)NULL, (LABEL*)NULL);
  689. X            return;
  690. X        }
  691. X        reread();
  692. X        /* fall into default case */
  693. X
  694. X    default:
  695. X        rescantoken();
  696. X        type = getexprlist();
  697. X        if (contlabel || breaklabel || (curfunc->f_name[0] != '*')) {
  698. X            addop(OP_POP);
  699. X            break;
  700. X        }
  701. X        addop(OP_SAVE);
  702. X        if (isassign(type) || (curfunc->f_name[1] != '\0')) {
  703. X            addop(OP_POP);
  704. X            break;
  705. X        }
  706. X        addop(OP_PRINTRESULT);
  707. X        break;
  708. X    }
  709. X    switch (gettoken()) {
  710. X        case T_RIGHTBRACE:
  711. X        case T_NEWLINE:
  712. X            rescantoken();
  713. X            break;
  714. X        case T_SEMICOLON:
  715. X            break;
  716. X        default:
  717. X            scanerror(T_SEMICOLON, "Semicolon expected");
  718. X            break;
  719. X    }
  720. X}
  721. X
  722. X
  723. X/*
  724. X * Read in an object definition statement.
  725. X * This is of the following form:
  726. X *    OBJ type [ '{' id [ ',' id ] ... '}' ]  [ objlist ].
  727. X * The OBJ keyword has already been read.
  728. X */
  729. Xstatic void
  730. Xgetobjstatement()
  731. X{
  732. X    char *name;            /* name of object type */
  733. X    int count;            /* number of elements */
  734. X    int index;            /* current index */
  735. X    int i;                /* loop counter */
  736. X    BOOL err;            /* error flag */
  737. X    int indices[MAXINDICES];    /* indices for elements */
  738. X
  739. X    err = FALSE;
  740. X    if (gettoken() != T_SYMBOL) {
  741. X        scanerror(T_SEMICOLON, "Object type name missing");
  742. X        return;
  743. X    }
  744. X    name = addliteral(tokenstring());
  745. X    if (gettoken() != T_LEFTBRACE) {
  746. X        rescantoken();
  747. X        getobjvars(name);
  748. X        return;
  749. X    }
  750. X    /*
  751. X     * Read in the definition of the elements of the object.
  752. X     */
  753. X    count = 0;
  754. X    for (;;) {
  755. X        if (gettoken() != T_SYMBOL) {
  756. X            scanerror(T_SEMICOLON, "Missing element name in OBJ statement");
  757. X            return;
  758. X        }
  759. X        index = addelement(tokenstring());
  760. X        for (i = 0; i < count; i++) {
  761. X            if (indices[i] == index) {
  762. X                scanerror(T_NULL, "Duplicate element name \"%s\"", tokenstring());
  763. X                err = TRUE;
  764. X                break;
  765. X            }
  766. X        }
  767. X        indices[count++] = index;
  768. X        switch (gettoken()) {
  769. X            case T_RIGHTBRACE:
  770. X                if (!err)
  771. X                    (void) defineobject(name, indices, count);
  772. X                switch (gettoken()) {
  773. X                    case T_SEMICOLON:
  774. X                    case T_NEWLINE:
  775. X                        rescantoken();
  776. X                        return;
  777. X                }
  778. X                rescantoken();
  779. X                getobjvars(name);
  780. X                return;
  781. X            case T_COMMA:
  782. X            case T_SEMICOLON:
  783. X            case T_NEWLINE:
  784. X                break;
  785. X            default:
  786. X                scanerror(T_SEMICOLON, "Bad object element definition");
  787. X                return;
  788. X        }
  789. X    }
  790. X}
  791. X
  792. X
  793. X/*
  794. X * Routine to collect a set of variables for the specified object type
  795. X * and initialize them as being that type of object.
  796. X * Here
  797. X *    objlist = name [ ',' name] ... ';'.
  798. X */
  799. Xstatic void
  800. Xgetobjvars(name)
  801. X    char *name;        /* object name */
  802. X{
  803. X    long index;        /* index for object */
  804. X
  805. X    index = checkobject(name);
  806. X    if (index < 0) {
  807. X        scanerror(T_SEMICOLON, "Object %s has not been defined yet", name);
  808. X        return;
  809. X    }
  810. X    for (;;) {
  811. X        (void) getidexpr(TRUE, TRUE);
  812. X        addopindex(OP_OBJINIT, index);
  813. X        switch (gettoken()) {
  814. X            case T_COMMA:
  815. X                break;
  816. X            case T_SEMICOLON:
  817. X            case T_NEWLINE:
  818. X                rescantoken();
  819. X                return;
  820. X            default:
  821. X                scanerror(T_SEMICOLON, "Bad OBJ statement");
  822. X                return;
  823. X        }
  824. X    }
  825. X}
  826. X
  827. X
  828. X/*
  829. X * Read a matrix definition statment for a one or more dimensional matrix.
  830. X * The MAT keyword has already been read.
  831. X */
  832. Xstatic void
  833. Xgetmatstatement()
  834. X{
  835. X    int dim;        /* dimension of matrix */
  836. X
  837. X    (void) getidexpr(FALSE, TRUE);
  838. X    if (gettoken() != T_LEFTBRACKET) {
  839. X        scanerror(T_SEMICOLON, "Missing left bracket for MAT");
  840. X        return;
  841. X    }
  842. X    dim = 1;
  843. X    for (;;) {
  844. X        (void) getassignment();
  845. X        switch (gettoken()) {
  846. X            case T_RIGHTBRACKET:
  847. X            case T_COMMA:
  848. X                rescantoken();
  849. X                addop(OP_ONE);
  850. X                addop(OP_SUB);
  851. X                addop(OP_ZERO);
  852. X                break;
  853. X            case T_COLON:
  854. X                (void) getassignment();
  855. X                break;
  856. X            default:
  857. X                rescantoken();
  858. X        }
  859. X        switch (gettoken()) {
  860. X            case T_RIGHTBRACKET:
  861. X                if (gettoken() != T_LEFTBRACKET) {
  862. X                    rescantoken();
  863. X                    addopindex(OP_MATINIT, (long) dim);
  864. X                    return;
  865. X                }
  866. X                /* proceed into comma case */
  867. X                /*FALLTHRU*/
  868. X            case T_COMMA:
  869. X                if (++dim <= MAXDIM)
  870. X                    break;
  871. X                scanerror(T_SEMICOLON, "Only %d dimensions allowed", MAXDIM);
  872. X                return;
  873. X            default:
  874. X                scanerror(T_SEMICOLON, "Illegal matrix definition");
  875. X                return;
  876. X        }
  877. X    }
  878. X}
  879. X
  880. X
  881. X/*
  882. X * Get a condition.
  883. X * condition = '(' assignment ')'.
  884. X */
  885. Xstatic void
  886. Xgetcondition()
  887. X{
  888. X    if (gettoken() != T_LEFTPAREN) {
  889. X        scanerror(T_SEMICOLON, "Missing left parenthesis for condition");
  890. X        return;
  891. X    }
  892. X    (void) getexprlist();
  893. X    if (gettoken() != T_RIGHTPAREN) {
  894. X        scanerror(T_SEMICOLON, "Missing right parenthesis for condition");
  895. X        return;
  896. X    }
  897. X}
  898. X
  899. X
  900. X/*
  901. X * Get an expression list consisting of one or more expressions,
  902. X * separated by commas.  The value of the list is that of the final expression.
  903. X * This is the top level routine for parsing expressions.
  904. X * Returns flags describing the type of assignment or expression found.
  905. X * exprlist = assignment [ ',' assignment ] ...
  906. X */
  907. Xstatic int
  908. Xgetexprlist()
  909. X{
  910. X    int    type;
  911. X
  912. X    type = getassignment();
  913. X    while (gettoken() == T_COMMA) {
  914. X        addop(OP_POP);
  915. X        (void) getassignment();
  916. X        type = EXPR_RVALUE;
  917. X    }
  918. X    rescantoken();
  919. X    return type;
  920. X}
  921. X
  922. X
  923. X/*
  924. X * Get an assignment (or possibly just an expression).
  925. X * Returns flags describing the type of assignment or expression found.
  926. X * assignment = lvalue '=' assignment
  927. X *    | lvalue '+=' assignment
  928. X *    | lvalue '-=' assignment
  929. X *    | lvalue '*=' assignment
  930. X *    | lvalue '/=' assignment
  931. X *    | lvalue '%=' assignment
  932. X *    | lvalue '//=' assignment
  933. X *    | lvalue '&=' assignment
  934. X *    | lvalue '|=' assignment
  935. X *    | lvalue '<<=' assignment
  936. X *    | lvalue '>>=' assignment
  937. X *    | lvalue '^=' assignment
  938. X *    | lvalue '**=' assignment
  939. X *    | orcond.
  940. X */
  941. Xstatic int
  942. Xgetassignment()
  943. X{
  944. X    int type;        /* type of expression */
  945. X    long op;        /* opcode to generate */
  946. X
  947. X    type = getaltcond();
  948. X    switch (gettoken()) {
  949. X        case T_ASSIGN:        op = 0; break;
  950. X        case T_PLUSEQUALS:    op = OP_ADD; break;
  951. X        case T_MINUSEQUALS:    op = OP_SUB; break;
  952. X        case T_MULTEQUALS:    op = OP_MUL; break;
  953. X        case T_DIVEQUALS:    op = OP_DIV; break;
  954. X        case T_SLASHSLASHEQUALS: op = OP_QUO; break;
  955. X        case T_MODEQUALS:    op = OP_MOD; break;
  956. X        case T_ANDEQUALS:    op = OP_AND; break;
  957. X        case T_OREQUALS:    op = OP_OR; break;
  958. X        case T_LSHIFTEQUALS:     op = OP_LEFTSHIFT; break;
  959. X        case T_RSHIFTEQUALS:     op = OP_RIGHTSHIFT; break;
  960. X        case T_POWEREQUALS:    op = OP_POWER; break;
  961. X
  962. X        case T_NUMBER:
  963. X        case T_IMAGINARY:
  964. X        case T_STRING:
  965. X        case T_SYMBOL:
  966. X        case T_OLDVALUE:
  967. X        case T_LEFTPAREN:
  968. X        case T_PLUSPLUS:
  969. X        case T_MINUSMINUS:
  970. X        case T_NOT:
  971. X            scanerror(T_NULL, "Missing operator");
  972. X            return type;
  973. X
  974. X        default:
  975. X            rescantoken();
  976. X            return type;
  977. X    }
  978. X    if (isrvalue(type)) {
  979. X        scanerror(T_NULL, "Illegal assignment");
  980. X        (void) getassignment();
  981. X        return (EXPR_RVALUE | EXPR_ASSIGN);
  982. X    }
  983. X    if (op)
  984. X        addop(OP_DUPLICATE);
  985. X    (void) getassignment();
  986. X    if (op) {
  987. X        addop(op);
  988. X    }
  989. X    addop(OP_ASSIGN);
  990. X    return (EXPR_RVALUE | EXPR_ASSIGN);
  991. X}
  992. X
  993. X
  994. X/*
  995. X * Get a possible conditional result expression (question mark).
  996. X * Flags are returned indicating the type of expression found.
  997. X * altcond = orcond [ '?' orcond ':' altcond ].
  998. X */
  999. Xstatic int
  1000. Xgetaltcond()
  1001. X{
  1002. X    int type;        /* type of expression */
  1003. X    LABEL donelab;        /* label for done */
  1004. X    LABEL altlab;        /* label for alternate expression */
  1005. X
  1006. X    type = getorcond();
  1007. X    if (gettoken() != T_QUESTIONMARK) {
  1008. X        rescantoken();
  1009. X        return type;
  1010. X    }
  1011. X    clearlabel(&donelab);
  1012. X    clearlabel(&altlab);
  1013. X    addoplabel(OP_JUMPEQ, &altlab);
  1014. X    (void) getorcond();
  1015. X    if (gettoken() != T_COLON) {
  1016. X        scanerror(T_SEMICOLON, "Missing colon for conditional expression");
  1017. X        return EXPR_RVALUE;
  1018. X    }
  1019. X    addoplabel(OP_JUMP, &donelab);
  1020. X    setlabel(&altlab);
  1021. X    (void) getaltcond();
  1022. X    setlabel(&donelab);
  1023. X    return EXPR_RVALUE;
  1024. X}
  1025. X
  1026. X
  1027. X/*
  1028. X * Get a possible conditional or expression.
  1029. X * Flags are returned indicating the type of expression found.
  1030. X * orcond = andcond [ '||' andcond ] ...
  1031. X */
  1032. Xstatic int
  1033. Xgetorcond()
  1034. X{
  1035. X    int type;        /* type of expression */
  1036. X    LABEL donelab;        /* label for done */
  1037. X
  1038. X    clearlabel(&donelab);
  1039. X    type = getandcond();
  1040. X    while (gettoken() == T_OROR) {
  1041. X        addoplabel(OP_CONDORJUMP, &donelab);
  1042. X        (void) getandcond();
  1043. X        type = EXPR_RVALUE;
  1044. X    }
  1045. X    rescantoken();
  1046. X    if (donelab.l_chain > 0)
  1047. X        setlabel(&donelab);
  1048. X    return type;
  1049. X}
  1050. X
  1051. X
  1052. X/*
  1053. X * Get a possible conditional and expression.
  1054. X * Flags are returned indicating the type of expression found.
  1055. X * andcond = relation [ '&&' relation ] ...
  1056. X */
  1057. Xstatic int
  1058. Xgetandcond()
  1059. X{
  1060. X    int type;        /* type of expression */
  1061. X    LABEL donelab;        /* label for done */
  1062. X
  1063. X    clearlabel(&donelab);
  1064. X    type = getrelation();
  1065. X    while (gettoken() == T_ANDAND) {
  1066. X        addoplabel(OP_CONDANDJUMP, &donelab);
  1067. X        (void) getrelation();
  1068. X        type = EXPR_RVALUE;
  1069. X    }
  1070. X    rescantoken();
  1071. X    if (donelab.l_chain > 0)
  1072. X        setlabel(&donelab);
  1073. X    return type;
  1074. X}
  1075. X
  1076. X
  1077. X/*
  1078. X * Get a possible relation (equality or inequality), or just an expression.
  1079. X * Flags are returned indicating the type of relation found.
  1080. X * relation = sum '==' sum
  1081. X *    | sum '!=' sum
  1082. X *    | sum '<=' sum
  1083. X *    | sum '>=' sum
  1084. X *    | sum '<' sum
  1085. X *    | sum '>' sum
  1086. X *    | sum.
  1087. X */
  1088. Xstatic int
  1089. Xgetrelation()
  1090. X{
  1091. X    int type;        /* type of expression */
  1092. X    long op;        /* opcode to generate */
  1093. X
  1094. X    type = getsum();
  1095. X    switch (gettoken()) {
  1096. X        case T_EQ: op = OP_EQ; break;
  1097. X        case T_NE: op = OP_NE; break;
  1098. X        case T_LT: op = OP_LT; break;
  1099. X        case T_GT: op = OP_GT; break;
  1100. X        case T_LE: op = OP_LE; break;
  1101. X        case T_GE: op = OP_GE; break;
  1102. X        default:
  1103. X            rescantoken();
  1104. X            return type;
  1105. X    }
  1106. X    (void) getsum();
  1107. X    addop(op);
  1108. X    return EXPR_RVALUE;
  1109. X}
  1110. X
  1111. X
  1112. X/*
  1113. X * Get an expression made up of sums of products.
  1114. X * Flags indicating the type of expression found are returned.
  1115. X * sum = product [ {'+' | '-'} product ] ...
  1116. X */
  1117. Xstatic int
  1118. Xgetsum()
  1119. X{
  1120. X    int type;        /* type of expression found */
  1121. X    long op;        /* opcode to generate */
  1122. X
  1123. X    type = getproduct();
  1124. X    for (;;) {
  1125. X        switch (gettoken()) {
  1126. X            case T_PLUS:    op = OP_ADD; break;
  1127. X            case T_MINUS:    op = OP_SUB; break;
  1128. X            default:
  1129. X                rescantoken();
  1130. X                return type;
  1131. X        }
  1132. X        (void) getproduct();
  1133. X        addop(op);
  1134. X        type = EXPR_RVALUE;
  1135. X    }
  1136. X}
  1137. X
  1138. X
  1139. X/*
  1140. X * Get the product of arithmetic or expressions.
  1141. X * Flags indicating the type of expression found are returned.
  1142. X * product = orexpr [ {'*' | '/' | '//' | '%'} orexpr ] ...
  1143. X */
  1144. Xstatic int
  1145. Xgetproduct()
  1146. X{
  1147. X    int type;        /* type of value found */
  1148. X    long op;        /* opcode to generate */
  1149. X
  1150. X    type = getorexpr();
  1151. X    for (;;) {
  1152. X        switch (gettoken()) {
  1153. X            case T_MULT:    op = OP_MUL; break;
  1154. X            case T_DIV:    op = OP_DIV; break;
  1155. X            case T_MOD:    op = OP_MOD; break;
  1156. X            case T_SLASHSLASH: op = OP_QUO; break;
  1157. X            default:
  1158. X                rescantoken();
  1159. X                return type;
  1160. X        }
  1161. X        (void) getorexpr();
  1162. X        addop(op);
  1163. X        type = EXPR_RVALUE;
  1164. X    }
  1165. X}
  1166. X
  1167. X
  1168. X/*
  1169. X * Get an expression made up of arithmetic or operators.
  1170. X * Flags indicating the type of expression found are returned.
  1171. X * orexpr = andexpr [ '|' andexpr ] ...
  1172. X */
  1173. Xstatic int
  1174. Xgetorexpr()
  1175. X{
  1176. X    int type;        /* type of value found */
  1177. X
  1178. X    type = getandexpr();
  1179. X    while (gettoken() == T_OR) {
  1180. X        (void) getandexpr();
  1181. X        addop(OP_OR);
  1182. X        type = EXPR_RVALUE;
  1183. X    }
  1184. X    rescantoken();
  1185. X    return type;
  1186. X}
  1187. X
  1188. X
  1189. X/*
  1190. X * Get an expression made up of arithmetic and operators.
  1191. X * Flags indicating the type of expression found are returned.
  1192. X * andexpr = shiftexpr [ '&' shiftexpr ] ...
  1193. X */
  1194. Xstatic int
  1195. Xgetandexpr()
  1196. X{
  1197. X    int type;        /* type of value found */
  1198. X
  1199. X    type = getshiftexpr();
  1200. X    while (gettoken() == T_AND) {
  1201. X        (void) getshiftexpr();
  1202. X        addop(OP_AND);
  1203. X        type = EXPR_RVALUE;
  1204. X    }
  1205. X    rescantoken();
  1206. X    return type;
  1207. X}
  1208. X
  1209. X
  1210. X/*
  1211. X * Get a shift or power expression.
  1212. X * Flags indicating the type of expression found are returned.
  1213. X * shift = term '^' shiftexpr
  1214. X *     | term '<<' shiftexpr
  1215. X *     | term '>>' shiftexpr
  1216. X *     | term.
  1217. X */
  1218. Xstatic int
  1219. Xgetshiftexpr()
  1220. X{
  1221. X    int type;        /* type of value found */
  1222. X    long op;        /* opcode to generate */
  1223. X
  1224. X    type = getterm();
  1225. X    switch (gettoken()) {
  1226. X        case T_POWER:        op = OP_POWER; break;
  1227. X        case T_LEFTSHIFT:    op = OP_LEFTSHIFT; break;
  1228. X        case T_RIGHTSHIFT:     op = OP_RIGHTSHIFT; break;
  1229. X        default:
  1230. X            rescantoken();
  1231. X            return type;
  1232. X    }
  1233. X    (void) getshiftexpr();
  1234. X    addop(op);
  1235. X    return EXPR_RVALUE;
  1236. X}
  1237. X
  1238. X
  1239. X/*
  1240. X * Get a single term.
  1241. X * Flags indicating the type of value found are returned.
  1242. X * term = lvalue
  1243. X *    | lvalue '[' assignment ']'
  1244. X *    | lvalue '++'
  1245. X *    | lvalue '--'
  1246. X *    | '++' lvalue
  1247. X *    | '--' lvalue
  1248. X *    | real_number
  1249. X *    | imaginary_number
  1250. X *    | '.'
  1251. X *    | string
  1252. X *    | '(' assignment ')'
  1253. X *    | function [ '(' [assignment  [',' assignment] ] ')' ]
  1254. X *    | '!' term
  1255. X *    | '+' term
  1256. X *    | '-' term.
  1257. X */
  1258. Xstatic int
  1259. Xgetterm()
  1260. X{
  1261. X    int type;        /* type of term found */
  1262. X
  1263. X    type = gettoken();
  1264. X    switch (type) {
  1265. X        case T_NUMBER:
  1266. X            addopindex(OP_NUMBER, tokennumber());
  1267. X            type = (EXPR_RVALUE | EXPR_CONST);
  1268. X            break;
  1269. X
  1270. X        case T_IMAGINARY:
  1271. X            addopindex(OP_IMAGINARY, tokennumber());
  1272. X            type = (EXPR_RVALUE | EXPR_CONST);
  1273. X            break;
  1274. X
  1275. X        case T_OLDVALUE:
  1276. X            addop(OP_OLDVALUE);
  1277. X            type = 0;
  1278. X            break;
  1279. X
  1280. X        case T_STRING:
  1281. X            addopptr(OP_STRING, tokenstring());
  1282. X            type = (EXPR_RVALUE | EXPR_CONST);
  1283. X            break;
  1284. X
  1285. X        case T_PLUSPLUS:
  1286. X            if (isrvalue(getterm()))
  1287. X                scanerror(T_NULL, "Bad ++ usage");
  1288. X            addop(OP_PREINC);
  1289. X            type = (EXPR_RVALUE | EXPR_ASSIGN);
  1290. X            break;
  1291. X
  1292. X        case T_MINUSMINUS:
  1293. X            if (isrvalue(getterm()))
  1294. X                scanerror(T_NULL, "Bad -- usage");
  1295. X            addop(OP_PREDEC);
  1296. X            type = (EXPR_RVALUE | EXPR_ASSIGN);
  1297. X            break;
  1298. X
  1299. X        case T_NOT:
  1300. X            (void) getterm();
  1301. X            addop(OP_NOT);
  1302. X            type = EXPR_RVALUE;
  1303. X            break;
  1304. X
  1305. X        case T_MINUS:
  1306. X            (void) getterm();
  1307. X            addop(OP_NEGATE);
  1308. X            type = EXPR_RVALUE;
  1309. X            break;
  1310. X
  1311. X        case T_PLUS:
  1312. X            (void) getterm();
  1313. X            type = EXPR_RVALUE;
  1314. X            break;
  1315. X
  1316. X        case T_LEFTPAREN:
  1317. X            type = getexprlist();
  1318. X            if (gettoken() != T_RIGHTPAREN)
  1319. X                scanerror(T_SEMICOLON, "Missing right parenthesis");
  1320. X            break;
  1321. X
  1322. X        case T_SYMBOL:
  1323. X            rescantoken();
  1324. X            type = getidexpr(TRUE, FALSE);
  1325. X            break;
  1326. X
  1327. X        case T_LEFTBRACKET:
  1328. X            scanerror(T_NULL, "Bad index usage");
  1329. X            type = 0;
  1330. X            break;
  1331. X
  1332. X        case T_PERIOD:
  1333. X            scanerror(T_NULL, "Bad element reference");
  1334. X            type = 0;
  1335. X            break;
  1336. X
  1337. X        default:
  1338. X            if (iskeyword(type)) {
  1339. X                scanerror(T_NULL, "Expression contains reserved keyword");
  1340. X                type = 0;
  1341. X                break;
  1342. X            }
  1343. X            rescantoken();
  1344. X            scanerror(T_NULL, "Missing expression");
  1345. X            type = 0;
  1346. X    }
  1347. X    switch (gettoken()) {
  1348. X        case T_PLUSPLUS:
  1349. X            if (isrvalue(type))
  1350. X                scanerror(T_NULL, "Bad ++ usage");
  1351. X            addop(OP_POSTINC);
  1352. X            return (EXPR_RVALUE | EXPR_ASSIGN);
  1353. X        case T_MINUSMINUS:
  1354. X            if (isrvalue(type))
  1355. X                scanerror(T_NULL, "Bad -- usage");
  1356. X            addop(OP_POSTDEC);
  1357. X            return (EXPR_RVALUE | EXPR_ASSIGN);
  1358. X        default:
  1359. X            rescantoken();
  1360. X            return type;
  1361. X    }
  1362. X}
  1363. X
  1364. X
  1365. X/*
  1366. X * Read in an identifier expressions.
  1367. X * This is a symbol name followed by parenthesis, or by square brackets or
  1368. X * element refernces.  The symbol can be a global or a local variable name.
  1369. X * Returns the type of expression found.
  1370. X */
  1371. Xstatic int
  1372. Xgetidexpr(okmat, autodef)
  1373. X    BOOL okmat, autodef;
  1374. X{
  1375. X    int type;
  1376. X    char name[SYMBOLSIZE+1];    /* symbol name */
  1377. X
  1378. X    type = 0;
  1379. X    if (!getid(name))
  1380. X        return type;
  1381. X    switch (gettoken()) {
  1382. X        case T_LEFTPAREN:
  1383. X            getcallargs(name);
  1384. X            type = EXPR_RVALUE;
  1385. X            break;
  1386. X        case T_ASSIGN:
  1387. X            autodef = TRUE;
  1388. X            /* fall into default case */
  1389. X        default:
  1390. X            rescantoken();
  1391. X            checksymbol(name, autodef);
  1392. X    }
  1393. X    /*
  1394. X     * Now collect as many element references and matrix index operations
  1395. X     * as there are following the id.
  1396. X     */
  1397. X    for (;;) {
  1398. X        switch (gettoken()) {
  1399. X            case T_LEFTBRACKET:
  1400. X                rescantoken();
  1401. X                if (!okmat)
  1402. X                    return type;
  1403. X                getmatargs();
  1404. X                type = 0;
  1405. X                break;
  1406. X            case T_PERIOD:
  1407. X                getelement();
  1408. X                type = 0;
  1409. X                break;
  1410. X            case T_LEFTPAREN:
  1411. X                scanerror(T_NULL, "Function calls not allowed as expressions");
  1412. X            default:
  1413. X                rescantoken();
  1414. X                return type;
  1415. X        }
  1416. X    }
  1417. X}
  1418. X
  1419. X
  1420. X/*
  1421. X * Read in a filename for a read or write command.
  1422. X * Both quoted and unquoted filenames are handled here.
  1423. X * The name must be terminated by an end of line or semicolon.
  1424. X * Returns TRUE if the filename was successfully parsed.
  1425. X */
  1426. Xstatic BOOL
  1427. Xgetfilename(name, msg_ok)
  1428. X    char name[PATHSIZE+1];
  1429. X    int msg_ok;        /* TRUE => ok to print error messages */
  1430. X{
  1431. X    tokenmode(TM_NEWLINES | TM_ALLSYMS);
  1432. X    switch (gettoken()) {
  1433. X        case T_STRING:
  1434. X        case T_SYMBOL:
  1435. X            break;
  1436. X        default:
  1437. X            if (msg_ok)
  1438. X                scanerror(T_SEMICOLON, "Filename expected");
  1439. X            return FALSE;
  1440. X    }
  1441. X    strcpy(name, tokenstring());
  1442. X    switch (gettoken()) {
  1443. X        case T_SEMICOLON:
  1444. X        case T_NEWLINE:
  1445. X        case T_EOF:
  1446. X            break;
  1447. X        default:
  1448. X            if (msg_ok)
  1449. X                scanerror(T_SEMICOLON, 
  1450. X                    "Missing semicolon after filename");
  1451. X            return FALSE;
  1452. X    }
  1453. X    return TRUE;
  1454. X}
  1455. X
  1456. X
  1457. X/*
  1458. X * Read the show command and display useful information.
  1459. X */
  1460. Xstatic void
  1461. Xgetshowcommand()
  1462. X{
  1463. X    char name[SYMBOLSIZE+1];
  1464. X
  1465. X    if ((gettoken() != T_SHOW) || (gettoken() != T_SYMBOL)) {
  1466. X        scanerror(T_SEMICOLON, "Bad syntax for SHOW command");
  1467. X        return;
  1468. X    }
  1469. X    strcpy(name, tokenstring());
  1470. X    switch (gettoken()) {
  1471. X        case T_NEWLINE:
  1472. X        case T_SEMICOLON:
  1473. X            break;
  1474. X        default:
  1475. X            scanerror(T_SEMICOLON, "Bad syntax for SHOW command");
  1476. X    }
  1477. X    switch ((int) stringindex("builtins\0globals\0functions\0objfuncs\0memory\0", name)) {
  1478. X        case 1:
  1479. X            showbuiltins();
  1480. X            break;
  1481. X        case 2:
  1482. X            showglobals();
  1483. X            break;
  1484. X        case 3:
  1485. X            showfunctions();
  1486. X            break;
  1487. X        case 4:
  1488. X            showobjfuncs();
  1489. X            break;
  1490. X        case 5:
  1491. X            mem_stats("");
  1492. X            break;
  1493. X        default:
  1494. X            scanerror(T_NULL, "Unknown SHOW parameter \"%s\"", name);
  1495. X    }
  1496. X}
  1497. X
  1498. X
  1499. X/*
  1500. X * Read in a set of matrix index arguments, surrounded with square brackets.
  1501. X * This also handles double square brackets for 'fast indexing'.
  1502. X */
  1503. Xstatic void
  1504. Xgetmatargs()
  1505. X{
  1506. X    int dim;
  1507. X
  1508. X    if (gettoken() != T_LEFTBRACKET) {
  1509. X        scanerror(T_NULL, "Matrix indexing expected");
  1510. X        return;
  1511. X    }
  1512. X    /*
  1513. X     * Parse all levels of the array reference
  1514. X     * Look for the 'fast index' first.
  1515. X     */
  1516. X    if (gettoken() == T_LEFTBRACKET) {
  1517. X        (void) getassignment();
  1518. X        if ((gettoken() != T_RIGHTBRACKET) ||
  1519. X            (gettoken() != T_RIGHTBRACKET)) {
  1520. X                scanerror(T_NULL, "Bad fast index usage");
  1521. X                return;
  1522. X        }
  1523. X        addop(OP_FIADDR);
  1524. X        return;
  1525. X    }
  1526. X    rescantoken();
  1527. X    /*
  1528. X     * Normal indexing with the indexes separated by commas.
  1529. X     */
  1530. X    dim = 1;
  1531. X    for (;;) {
  1532. X        (void) getassignment();
  1533. X        switch (gettoken()) {
  1534. X            case T_RIGHTBRACKET:
  1535. X                if (gettoken() != T_LEFTBRACKET) {
  1536. X                    rescantoken();
  1537. X                    addopindex(OP_INDEXADDR, (long) dim);
  1538. X                    return;
  1539. X                }
  1540. X                /* proceed into comma case */
  1541. X                /*FALLTHRU*/
  1542. X            case T_COMMA:
  1543. X                if (++dim > MAXDIM)
  1544. X                    scanerror(T_NULL, "Too many dimensions for array reference");
  1545. X                break;
  1546. X            default:
  1547. X                rescantoken();
  1548. X                scanerror(T_NULL, "Missing right bracket in array reference");
  1549. X                return;
  1550. X        }
  1551. X    }
  1552. X}
  1553. X
  1554. X
  1555. X/*
  1556. X * Get an element of an object reference.
  1557. X * The leading period which introduces the element has already been read.
  1558. X */
  1559. Xstatic void
  1560. Xgetelement()
  1561. X{
  1562. X    long index;
  1563. X    char name[SYMBOLSIZE+1];
  1564. X
  1565. X    if (!getid(name))
  1566. X        return;
  1567. X    index = findelement(name);
  1568. X    if (index < 0) {
  1569. X        scanerror(T_NULL, "Element \"%s\" is undefined", name);
  1570. X        return;
  1571. X    }
  1572. X    addopindex(OP_ELEMADDR, index);
  1573. X}
  1574. X
  1575. X
  1576. X/*
  1577. X * Read in a single symbol name and copy its value into the given buffer.
  1578. X * Returns TRUE if a valid symbol id was found.
  1579. X */
  1580. Xstatic BOOL
  1581. Xgetid(buf)
  1582. X    char buf[SYMBOLSIZE+1];
  1583. X{
  1584. X    int type;
  1585. X
  1586. X    type = gettoken();
  1587. X    if (iskeyword(type)) {
  1588. X        scanerror(T_NULL, "Reserved keyword used as symbol name");
  1589. X        type = T_SYMBOL;
  1590. X    }
  1591. X    if (type != T_SYMBOL) {
  1592. X        rescantoken();
  1593. X        scanerror(T_NULL, "Symbol name expected");
  1594. X        *buf = '\0';
  1595. X        return FALSE;
  1596. X    }
  1597. X    strncpy(buf, tokenstring(), SYMBOLSIZE);
  1598. X    buf[SYMBOLSIZE] = '\0';
  1599. X    return TRUE;
  1600. X}
  1601. X
  1602. X
  1603. X/*
  1604. X * Check a symbol name to see if it is known and generate code to reference it.
  1605. X * The symbol can be either a parameter name, a local name, or a global name.
  1606. X * If autodef is true, we automatically define the name as a global symbol
  1607. X * if it is not yet known.
  1608. X */
  1609. Xstatic void
  1610. Xchecksymbol(name, autodef)
  1611. X    char *name;        /* symbol name to be checked */
  1612. X    BOOL autodef;
  1613. X{
  1614. X    switch (symboltype(name)) {
  1615. X        case SYM_LOCAL:
  1616. X            addopindex(OP_LOCALADDR, (long) findlocal(name));
  1617. X            return;
  1618. X        case SYM_PARAM:
  1619. X            addopindex(OP_PARAMADDR, (long) findparam(name));
  1620. X            return;
  1621. X        case SYM_GLOBAL:
  1622. X            addopptr(OP_GLOBALADDR, (char *) findglobal(name));
  1623. X            return;
  1624. X    }
  1625. X    /*
  1626. X     * The symbol is not yet defined.
  1627. X     * If we are at the top level and we are allowed to, then define it.
  1628. X     */
  1629. X    if ((curfunc->f_name[0] != '*') || !autodef) {
  1630. X        scanerror(T_NULL, "\"%s\" is undefined", name);
  1631. X        return;
  1632. X    }
  1633. X    (void) addglobal(name);
  1634. X    addopptr(OP_GLOBALADDR, (char *) findglobal(name));
  1635. X}
  1636. X
  1637. X
  1638. X/*
  1639. X * Get arguments for a function call.
  1640. X * The name and beginning parenthesis has already been seen.
  1641. X * callargs = [ [ '&' ] assignment  [',' [ '&' ] assignment] ] ')'.
  1642. X */
  1643. Xstatic void
  1644. Xgetcallargs(name)
  1645. X    char *name;        /* name of function */
  1646. X{
  1647. X    long index;        /* function index */
  1648. X    long op;        /* opcode to add */
  1649. X    int argcount;        /* number of arguments */
  1650. X    BOOL addrflag;
  1651. X
  1652. X    op = OP_CALL;
  1653. X    index = getbuiltinfunc(name);
  1654. X    if (index < 0) {
  1655. X        op = OP_USERCALL;
  1656. X        index = adduserfunc(name);
  1657. X    }
  1658. X    if (gettoken() == T_RIGHTPAREN) {
  1659. X        if (op == OP_CALL)
  1660. X            builtincheck(index, 0);
  1661. X        addopfunction(op, index, 0);
  1662. X        return;
  1663. X    }
  1664. X    rescantoken();
  1665. X    argcount = 0;
  1666. X    for (;;) {
  1667. X        argcount++;
  1668. X        addrflag = (gettoken() == T_AND);
  1669. X        if (!addrflag)
  1670. X            rescantoken();
  1671. X        if (!islvalue(getassignment()) && addrflag)
  1672. X            scanerror(T_NULL, "Taking address of non-variable");
  1673. X        if (!addrflag && (op != OP_CALL))
  1674. X            addop(OP_GETVALUE);
  1675. X        switch (gettoken()) {
  1676. X            case T_RIGHTPAREN:
  1677. X                if (op == OP_CALL)
  1678. X                    builtincheck(index, argcount);
  1679. X                addopfunction(op, index, argcount);
  1680. X                return;
  1681. X            case T_COMMA:
  1682. X                break;
  1683. X            default:
  1684. X                scanerror(T_SEMICOLON, "Missing right parenthesis in function call");
  1685. X                return;
  1686. X        }
  1687. X    }
  1688. X}
  1689. X
  1690. X/* END CODE */
  1691. END_OF_FILE
  1692. if test 35857 -ne `wc -c <'codegen.c'`; then
  1693.     echo shar: \"'codegen.c'\" unpacked with wrong size!
  1694. fi
  1695. # end of 'codegen.c'
  1696. fi
  1697. echo shar: End of archive 19 \(of 21\).
  1698. cp /dev/null ark19isdone
  1699. MISSING=""
  1700. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
  1701.     if test ! -f ark${I}isdone ; then
  1702.     MISSING="${MISSING} ${I}"
  1703.     fi
  1704. done
  1705. if test "${MISSING}" = "" ; then
  1706.     echo You have unpacked all 21 archives.
  1707.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1708. else
  1709.     echo You still need to unpack the following archives:
  1710.     echo "        " ${MISSING}
  1711. fi
  1712. ##  End of shell archive.
  1713. exit 0
  1714.