r313: *** empty log message ***
[ctsim.git] / libctgraphics / pol.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   POL - Problem Oriented Language                    
5 **
6 **  This is part of the CTSim program
7 **  Copyright (C) 1983-2000 Kevin Rosenberg
8 **
9 **  $Id: pol.cpp,v 1.5 2000/12/25 21:54:26 kevin Exp $
10 **
11 **  This program is free software; you can redistribute it and/or modify
12 **  it under the terms of the GNU General Public License (version 2) as
13 **  published by the Free Software Foundation.
14 **
15 **  This program is distributed in the hope that it will be useful,
16 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 **  GNU General Public License for more details.
19 **
20 **  You should have received a copy of the GNU General Public License
21 **  along with this program; if not, write to the Free Software
22 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 ******************************************************************************/
24 /*                                                                      */
25 /*----------------------------------------------------------------------*/
26
27 #include "ct.h"\r
28 #include <math.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 #include "ctsupport.h"
32 #include "pol.h"
33
34
35 static const int HASHSIZE=100;
36
37
38 // Tables words stored with install() & found with lookup() 
39 static SYMBOL *skiptable[HASHSIZE];             // words to ignore and skip 
40 static SYMBOL *cmdtable[HASHSIZE];              // pol parameter commands 
41 static SYMBOL *usertable[HASHSIZE];             // user defined symbols 
42
43 static struct token_st token;                           // current token 
44 \r
45
46 static struct metachar {
47     char eoc;           /* end of command character */
48     char str;           /* string delimiter */
49     char com;           /* comment character */
50     char cmd;           /* pol parameter command character */
51     char prg;           /* program load character */
52     char con;           /* continuation across newline character */
53     char out;           /* character that delimits output to terminal */
54     char ter;           /* character indicates insertion of input from terminal */
55     char inb;           /* input from graphics device */
56 } meta;
57
58 \r
59 // current pol state 
60 static struct pol_st {
61     char skipchars[MAXSKIPCHAR];        // characters to skip 
62     int nl_eoc;                         // TRUE if newline character ends a command 
63     int trace;                          // TRUE if trace is on 
64 } pol;
65
66 struct key {
67     char *keyword;
68     int  code;
69 };
70
71 // Internal codes for pol commands 
72 enum {\r
73    PC_EOC = 1,
74    PC_STR,
75    PC_COM,
76    PC_CMD,
77    PC_PRG,
78    PC_CON,      
79    PC_OUT,
80    PC_TER,
81    PC_INB,         
82    PC_NL_EOC,
83    PC_NL_NEOC,
84    PC_TRON,
85    PC_TROFF,
86    PC_FILE,
87    PC_DUMP,
88 };
89 \r
90 static struct key cmdlist[] = {
91   {     "eoc",  PC_EOC,},
92   {     "str",  PC_STR,},
93   {     "com",  PC_COM,},
94   {     "cmd",  PC_CMD,},
95   {     "prg",  PC_PRG,},
96   {     "con",  PC_CON,},
97   {     "out",  PC_OUT,},
98   {     "ter",  PC_TER,},
99   {     "inb",  PC_INB,},
100
101   {     "nl_eoc",PC_NL_EOC,},
102   {     "nl_neoc", PC_NL_NEOC,},
103   {     "tron",  PC_TRON,},
104   {     "troff", PC_TROFF,},
105   {     "file",  PC_FILE,},
106   {     "dump",  PC_DUMP,},
107 };
108
109 const int NUMCMD = (sizeof(cmdlist) / sizeof (struct key));
110 \r
111
112 static int skiptok(char term[]);
113 static int pol_tok(struct token_st *token);
114 static void dumptok(struct token_st *token);
115
116
117 static int getpol_tok(struct token_st *token);
118 static int getcmd(void);
119 static int gettok (TOKEN *tok);
120 static void getblank(char *s, int toksiz);
121 static int getalpha(char *s, int toksiz);
122 static void getquote(char *qs, int toksiz);
123 static void getescape(char *s, int delim, int toksiz);
124 static int getnumber (char str[], int strsize, double *fnum, int *inum);
125 static void eatline(void);
126 static int type(int c);
127 static void inittable(SYMBOL *table[]);
128 static void freetable(SYMBOL *table[]);
129 static int hash(char *s);
130 static SYMBOL *lookup(SYMBOL *table[], char *s);
131 static SYMBOL *install(SYMBOL *table[], char *s, int def);
132 static int pol_getch(FILE *fp);
133
134
135 void pol_init (void)
136 {
137         meta.eoc    = SEMICOL;
138         meta.str    = DQUOTE;
139         meta.com    = SHARP;
140         meta.cmd    = EXCLAM;
141         meta.prg    = ATSIGN;
142         meta.con    = AMPERSAND;
143         meta.out    = DOLLAR;
144         meta.ter    = PERCENT;
145         meta.inb    = LBRACK;
146
147         pol.nl_eoc = TRUE;
148         pol.skipchars[0] = EOS;
149
150         inittable (cmdtable);           /* initialize symbol tables */
151         inittable (usertable);
152         inittable (skiptable);
153
154         for (unsigned int i = 0; i < NUMCMD; i++)
155             install (cmdtable, cmdlist[i].keyword, cmdlist[i].code);
156
157         token.ready = FALSE;            /* no token read yet */
158 }
159
160 /* pol_skpword (w)
161  *
162  * char *w - word for pol to ignore and skip over in input
163  *
164  * pol_tok() compares all tokens to words given to this routine. If it finds it,
165  * it will immediately read another token. 
166  */
167
168 void 
169 pol_skpword (char *w)
170 {
171         if (install (skiptable, w, 0) == NULL)
172             sys_error (ERR_SEVERE, "Too many skip words defined");
173 }
174
175 /* pol_skpchar (s)
176  *
177  * skip all characters that appear in string s
178  */
179 void 
180 pol_skpchar (char *s)
181 {
182         strncpy (pol.skipchars, s, MAXSKIPCHAR);
183 }
184
185 /* pol_install (str, code)
186  *
187  * char *str - token string to install
188  * int code  - code to return for token
189  *
190  * pol_tok() looks for these user defined tokens.  If it finds one,
191  * it stores the tokens code in the token structure and returns TT_USERTOK
192  */
193 int 
194 pol_install (char *str, int code)
195 {
196     if (install (usertable, str, code) == NULL)
197         {
198             sys_error  (ERR_SEVERE, "Out of memory installing user tokens");
199             return (FALSE);
200         }
201     
202     return(TRUE);
203 }
204
205 /* get_word - matches tokens on a letter by letter basis
206  *
207  * char *search - string to search for
208  * int  nlet    - maximum number of chars to search for match
209  */
210
211 int 
212 pol_word (char *search, int nlet)
213 {
214         pol_tok (&token);
215         if (pol.trace == TRUE)
216             printf ("matching current token %s against word %s\n", token.tokstr, search);
217
218         if (strncasecmp (search, token.tokstr, nlet) == 0) {
219             dumptok (&token);
220             return (TRUE);
221         } else
222             return (FALSE);
223 }
224
225 /* pol_usertok (str,code)
226  *      see if current token is a user defined token set with pol_install()
227  *
228  *    char *str - token string as read from input
229  *    int *code - returned code for user defined symbol
230  *    return value - TRUE if current token has been user defined
231  *                   FALSE if current token is not user defined
232  */
233 int 
234 pol_usertok (char *str, int *code)
235 {
236         pol_tok (&token);
237
238         if (pol.trace == TRUE)
239             printf ("checking if current token '%s' is user defined\n", token.tokstr);
240
241         if (token.type == TT_USERTOK) {
242             *code = token.code;
243             strcpy (str, token.tokstr);
244             dumptok (&token);
245             return (TRUE);
246         } else {
247             *code = 0;
248             return (FALSE);
249         }
250 }
251
252 /* isstring (s) - returns TRUE if current token is a string
253  *
254  * char *s - pointer to place to store token string
255 */
256  
257 int 
258 pol_string (char *str)
259 {
260         pol_tok (&token);
261
262         if (token.type == TT_STRING) {
263             strcpy (str, token.tokstr);
264             dumptok (&token);
265             return (TRUE);
266         } else
267             return (FALSE);
268 }
269
270 /* pol_integer - test for an integer
271  *
272  * int *n:      returned integer value
273  * int typecode = TT_INT if accept only integer values
274  *              = TT_REAL if accept both real and integer values
275  * int boundcode= TRUE if force to lie between boundries
276  *              = FALSE can take any value it likes
277  * int bb1:     lower bound
278  * int bb2:     upper bound
279 */
280 int 
281 pol_integer (int *n, int typecode, int boundcode, int bb1, int bb2)
282 {
283         pol_tok (&token);
284
285         if (pol.trace == TRUE)
286             printf ("checking if current token %s is an integer\n", token.tokstr);
287
288         if (token.type == TT_INT || token.type == TT_REAL) {
289            if (boundcode == TRUE) {
290                 if (token.inum < bb1)
291                    *n = bb1;
292                 else if (token.inum > bb2)
293                    *n = bb2;
294                 else
295                     *n = token.inum;
296             } else
297                 *n = token.inum;
298             dumptok (&token);
299             return (TRUE);
300         }
301         *n = 0;
302         return (FALSE);
303 }
304
305 int 
306 pol_float (double *n, double typecode, double boundcode, double bb1, double bb2)
307 {
308         pol_tok (&token);
309
310         if (pol.trace == TRUE)
311             printf ("checking if current token %s is an floating point number\n", token.tokstr);
312
313         if (token.type == TT_INT || token.type == TT_REAL) {
314            if (boundcode == TRUE) {
315                 if (token.fnum < bb1)
316                    *n = bb1;
317                 else if (token.fnum > bb2)
318                    *n = bb2;
319                 else
320                     *n = token.fnum;
321             } else
322                 *n = token.fnum;
323             dumptok (&token);
324             return (TRUE);
325         }
326         *n = 0.0;
327         return (FALSE);
328 }
329
330 /*----------------------------------------------------------------------*/
331 /* pol_skip() - skip over any token except for end of command sequence  */
332 /*                                                                      */
333 /*              returns TRUE if succesful skip                          */
334 /*              returns FALSE if already at end of command or EOF       */
335 /*----------------------------------------------------------------------*/
336
337 int pol_skip(void)
338 {
339         char term[5];           /* string of characters not to skip */
340
341         term[0] = meta.eoc;
342         if (pol.nl_eoc == TRUE) {
343             term[1] = NEWLINE;
344             term[2] = EOS;
345         } else
346             term[1] = EOS;
347
348         return (skiptok (term));
349 }
350
351 void pol_reader(void)
352 {
353         while (pol_skip() == TRUE)
354             ;
355
356         dumptok (&token);               /* skip end of command token */
357 }
358
359 /* skiptok (term) - skip a token unless the first character of a token is
360  *                  in the string of terminators, term.
361  * char *term - string of termination characters, don't skip these characters
362  *              skiptok() also does NOT skip TT_EOF
363  * returns (TRUE) if succesful skip of a token
364  * returns (FALSE) if didn't skip, read termination character or TT_EOF
365  */
366
367 static int 
368 skiptok (char term[])
369 {
370         pol_tok (&token);
371
372         if (token.type == TT_EOF
373         || (token.type == TT_SPECLCHAR && strchr(term, token.tokstr[0]) != NULL))
374                 return (FALSE);
375         else {
376             dumptok (&token);
377             return (TRUE);
378         }
379 }
380
381 static int 
382 pol_tok (struct token_st *token)
383 {
384         if (token->ready == FALSE)
385             getpol_tok(token);
386         else
387             if (token->type == TT_EOF && pol_lookchar() != EOF)
388                 getpol_tok(token);
389         return (token->type);
390 }
391
392 static void 
393 dumptok (struct token_st *token)
394 {
395         if (token->ready == FALSE)
396             getpol_tok(token);
397         token->ready = FALSE;
398 }
399
400 static int 
401 getpol_tok (struct token_st *token)
402 {
403         SYMBOL *sym;
404
405         token->ready = FALSE;
406 nexttok:
407         gettok (token);
408
409         if (token->type == TT_BLANK)
410             goto nexttok;
411         if (token->type == TT_SPECLCHAR) {
412             if (strchr(pol.skipchars, token->tokstr[0]) != NULL)
413                 goto nexttok;
414             if (token->tokstr[0] == NEWLINE)
415                 goto nexttok;
416             if (token->tokstr[0] == meta.cmd) {
417                 getcmd();
418                 goto nexttok;
419             }
420             if (token->tokstr[0] == meta.com) {         /* skip comment */
421                 eatline ();
422                 goto nexttok;
423             }
424             if (token->tokstr[0] == meta.out) {
425                 getescape(token->tokstr, meta.out, MAXTOK);
426                 fputs (token->tokstr, stderr);
427                 goto nexttok;
428             }
429             if (token->tokstr[0] == meta.con) {         /* continuation across NEWLINE */
430                 while (pol_lookchar() == BLANK || pol_lookchar() == TAB)
431                     pol_inchar();
432                 if (pol_lookchar() == NEWLINE)
433                     pol_inchar();
434             }
435             if (token->tokstr[0] == meta.ter) {         /* get input from terminal */
436                 pol_usefile (P_USE_FILE, "");
437                 pol_tok (token);
438                 pol_closefile();
439                 return (token->type);
440             }
441         }
442
443         /* look for filler words */
444
445         if (lookup (skiptable, token->tokstr) != NULL)  /* ignore words in skip table */
446             goto nexttok;
447
448         /* look for user defined symbols */
449
450         if ((sym = lookup (usertable, token->tokstr)) != NULL) {
451             token->type = TT_USERTOK;
452             token->code = sym->code;
453         } else
454             token->code = 0;
455
456         if (pol.trace == TRUE)
457             printf ("Read token '%s', type = %d\n", token->tokstr, token->type);
458
459         return (token->type);
460 }
461
462
463 static int getcmd(void)
464 {
465         int tt, found;
466         char str[MAXTOK+1];
467         SYMBOL *cmd;
468         TOKEN tok;
469
470         tt = getalpha (str, MAXTOK);
471         if (tt == TT_ERROR) {
472             sys_error (ERR_WARNING, "Error in POL parameter command");
473             pol_reader();
474             return(FALSE);
475         }
476         if ((cmd = lookup (cmdtable,str)) == NULL) {
477             sys_error  (ERR_WARNING, "POL: Unrecognized command %s", cmd);
478             pol_reader();
479             return (FALSE);
480         } else {
481             found = FALSE;
482             switch (cmd->code) {
483                 case PC_TRON:
484                     pol.trace = TRUE;
485                     found = TRUE;
486                     break;
487                 case PC_TROFF:
488                     pol.trace = FALSE;
489                     found = TRUE;
490                     break;
491                 case PC_FILE:
492                     found = TRUE;
493                     tt = gettok (&tok);
494                     pol_usefile (P_USE_FILE, tok.tokstr);
495                     break;
496                 case PC_NL_EOC:
497                     found = TRUE;
498                     pol.nl_eoc = TRUE;
499                     break;
500                 case PC_NL_NEOC:
501                     found = TRUE;
502                     pol.nl_eoc = FALSE;
503                     break;
504                 case PC_DUMP:
505                     found = TRUE;
506                     printf("eoc = %c  str = %c  com = %c  cmd = %c  prg = %c\n",
507                         meta.eoc, meta.str, meta.com, meta.cmd, meta.prg);
508                     printf("con = %c  out = %c  ter = %c  inb = %c\n",
509                         meta.con, meta.out, meta.ter, meta.inb);
510                     break; 
511             }
512             if (found == FALSE) {
513                 tt = gettok (&tok);
514                 if (tt != TT_SPECLCHAR) {
515                     sys_error (ERR_SEVERE, "POL: Illegal command character");
516                     return (FALSE);
517                 }
518                 switch(cmd->code) {
519                     case PC_EOC:
520                         meta.eoc = tok.tokstr[0];
521                         break;
522                     case PC_STR:
523                         meta.str = tok.tokstr[0];
524                         break;
525                     case PC_COM:
526                         meta.com = tok.tokstr[0];
527                         break;
528                     case PC_CMD:
529                         meta.cmd = tok.tokstr[0];
530                         break;
531                     case PC_PRG:
532                         meta.prg = tok.tokstr[0];
533                         break;
534                     case PC_CON:
535                         meta.con = tok.tokstr[0];
536                         break;
537                     case PC_OUT:
538                         meta.out = tok.tokstr[0];
539                         break;
540                     case PC_TER:
541                         meta.ter = tok.tokstr[0];
542                         break;
543                     case PC_INB:
544                         meta.inb = tok.tokstr[0];
545                         break;
546                     default:
547                         printf("command not implemented\n");
548                         break;
549                 }                               /* switch (tok->type) */
550             }                                   /* if (found == FALSE) */
551             pol_reader();                       /* clean up command */
552         }                                       /* if legal command */
553
554         return (TRUE);
555 }
556
557
558 static int 
559 gettok (TOKEN *tok)
560 {
561         int c, toktype;
562         int inum;
563         double fnum;
564         int toksiz = MAXTOK;            /* maximum length of token string */
565
566         while ((c = pol_inchar()) == BLANK || c == TAB)
567             ;
568         pol_ungetch (c);
569
570         c = pol_lookchar();
571         toktype = type(c);
572
573         fnum = 0.0;
574         inum = 0;
575
576         if (c == BLANK || c == TAB) {                   /* skip white space */
577             getblank(tok->tokstr, toksiz);
578             toktype = TT_BLANK;
579         } else if (toktype == LETTER) {
580             toktype = getalpha (tok->tokstr, toksiz);
581         } else if (c == meta.str) {                     /* quoted string */
582             getquote (tok->tokstr, toksiz);
583             toktype = TT_STRING;
584         } else if (type(c) == DIGIT || c == PLUS || c == HYPHEN || c == PERIOD) {
585             toktype = getnumber (tok->tokstr, toksiz, &fnum, &inum);
586         } else if (c == EOF) {
587             tok->tokstr[0] = EOS;
588             toktype = TT_EOF;
589         } else {
590             c = pol_inchar();
591             tok->tokstr[0] = c;
592             tok->tokstr[1] = EOS;
593             toktype = TT_SPECLCHAR;
594         }
595
596         tok->type = toktype;
597         tok->ready = TRUE;
598         if (tok->type == TT_REAL || tok->type == TT_INT) {
599             tok->fnum = fnum;
600             tok->inum = inum;
601         } else {
602             tok->fnum = 0.0;
603             tok->inum = 0;
604         }
605
606         return (toktype);
607 }
608
609
610 static void 
611 getblank (char *s, int toksiz)
612 {
613         int c;
614
615         while ((c = pol_inchar()) == BLANK || c == TAB)
616               ;
617         pol_ungetch(c);
618
619         s[0] = BLANK;
620         s[1] = EOS;
621 }
622
623
624 static int 
625 getalpha (char *s, int toksiz)
626 {
627         int i, chartype, alphatype;
628
629         if (type(pol_lookchar()) != LETTER) {
630             s[0] = EOS;
631             return (TT_ERROR);
632         }
633
634         alphatype = TT_ALPHA;
635         for (i = 0; i < toksiz; i++) {          /* get alphanumeric token */
636             s[i] = pol_inchar();
637             chartype = type (s[i]);
638             if (chartype != LETTER && chartype != DIGIT)
639                 break;
640             if (chartype == DIGIT)
641                 alphatype = TT_ALPNUM;
642         }
643         pol_ungetch(s[i]);
644
645         if (i >= toksiz)
646             sys_error (ERR_SEVERE, "POL token too long.");
647
648         s[i] = EOS;                     /* terminate token */
649         return (alphatype);
650 }
651
652
653 /* getquote - get quoted string from file */
654 /* have already gotten delimiter in qs[0] */
655 static void 
656 getquote (char *qs, int toksiz)
657 {
658         int delim;
659
660         delim = pol_inchar();                   /* char = delimiter */
661         getescape(qs, delim, toksiz);
662 }
663
664
665 static void 
666 getescape (     /* reads up to delim */
667     char *s,
668     int delim,
669     int toksiz
670 )
671 {
672         int i, c;
673
674         for (i = 0; (c = pol_inchar()) != delim; i++) {
675             if (c == NEWLINE) {
676                 sys_error (ERR_WARNING, "Missing closing delimiter.");
677                 break;
678             }
679             if (i >= toksiz) {
680                 sys_error (ERR_SEVERE, "string too long.");
681                 break;
682             }
683             if (c == EOF) {
684                 pol_ungetch(c);
685                 sys_error (ERR_SEVERE, "end of file inside quotation");
686                 break;
687             } else if (c == BSLASH) {   /* escape character */
688                 s[i++] = c;
689                 c = pol_inchar();               /* get escaped character */
690             }
691             s[i] = c;
692         }
693         s[i] = EOS;
694 }
695
696 void 
697 gettext (char *str, int lim)
698 {
699         int c, i;
700
701         while ((c = pol_inchar()) == BLANK || c == TAB)
702             ;
703         pol_ungetch (c);
704
705         for (i = 0; i < lim && (c = pol_inchar()) != EOF && c != NEWLINE; i++)
706             str[i] = c;
707         pol_ungetch (c);
708         str[i] = EOS;
709 }
710
711 /*----------------------------------------------*/
712 /* Get a number for gettok()                    */
713 /*----------------------------------------------*/
714
715 static int 
716 getnumber (
717     char str[],                         /* string to return token in */
718     int strsize,                                /* maximum length of token string */
719     double *fnum,                               /* floating point value of number read */
720     int *inum                           /* integer value of number read */
721 )
722 {
723         int c, sp, isSigned;
724         double sign, whole, frac, powerof10, exp, expsign;
725
726         sp = 0;
727         sign = 1.0;
728         isSigned = FALSE;               /* TRUE if number prefixed by '+' or '-' */ 
729         *fnum = 0.0;
730         *inum = 0;
731         str[0] = EOS;
732
733         c = pol_inchar();
734         if (c == HYPHEN) {
735             str[sp++] = c;
736             isSigned = TRUE;
737             sign = -1.0;
738         } else if (c == PLUS) {
739             str[sp++] = c;
740             isSigned = TRUE;
741             sign = 1.0;
742         } else if (c == PERIOD) {
743             if (type(pol_lookchar()) != DIGIT) {
744                 str[0] = PERIOD;
745                 str[1] = EOS;
746                 return (TT_SPECLCHAR);
747             } else
748                 pol_ungetch (PERIOD);
749         } else if (type(c) != DIGIT) {
750             pol_ungetch (c);
751             return (TT_ERROR);
752         } else
753             pol_ungetch (c);
754
755         if (isSigned == TRUE) {
756             c = pol_lookchar();
757             if (c == PERIOD) {
758                 pol_inchar();           /* get period */
759                 c = pol_lookchar();             /* look at character past period */
760                 pol_ungetch (PERIOD);   /* put back period */
761                 if (type(c) != DIGIT) {
762                     str[sp] = EOS;
763                     return (TT_SPECLCHAR);
764                 }
765             } else if (type (c) != DIGIT) {
766                 str[sp] = EOS;
767                 return (TT_SPECLCHAR);
768             }
769         }
770
771         whole = 0.0;
772         while (type(c = pol_inchar()) == DIGIT) {
773             if (sp < strsize)
774                 str[sp++] = c;
775             whole = 10.0 * whole + (c - '0');
776         }
777         pol_ungetch (c);                /* put back non-numeric character */
778
779         if (c != PERIOD && tolower(c) != 'e') {
780             str[sp] = EOS;
781             *fnum = whole * sign;
782             if (*fnum < MIN_INT)
783                 *inum = MIN_INT;
784             else if (*fnum > MAX_INT)
785                 *inum = MAX_INT;
786             else
787                 *inum = (int) *fnum;
788             return (TT_INT);
789         }
790
791         if (pol_lookchar() == PERIOD) {
792             pol_inchar();
793             if (sp < strsize)
794                 str[sp++] = PERIOD;
795         }
796
797         frac = 0.0;
798         powerof10 = 10.0;
799
800         while (type(c = pol_inchar()) == DIGIT) {
801             if (sp < strsize)
802                 str[sp++] = c;
803             frac += (double) (c - '0') / powerof10;
804             powerof10 *= 10.0;
805         }
806         pol_ungetch (c);
807
808         exp = 0.0;
809         expsign = 1.0;
810         c = pol_inchar();
811         if (tolower(c) != 'e')
812             pol_ungetch (c);
813         else {
814             if (sp < strsize)
815                 str[sp++] = c;
816             if ((c = pol_inchar()) == PLUS) {
817                 if (sp < strsize)
818                     str[sp++] = c;
819                 expsign = 1.0;
820             } else if (c == HYPHEN) {
821                 if (sp < strsize)
822                     str[sp++] = c;
823                 expsign = -1.0;
824             } else if (type(c) != DIGIT) {
825                 --sp;                           /* erase 'e' */
826                 pol_ungetch (c);
827                 pol_ungetch ('e');
828                 goto getnumexit;
829             } else
830                 pol_ungetch(c);
831
832             exp = 0;
833             while (type(c = pol_inchar()) == DIGIT) {
834                 if (sp < strsize)
835                     str[sp++] = c;
836                 exp = 10 * exp + (c - '0');
837             }
838             pol_ungetch (c);
839         }
840
841 getnumexit:
842         str[sp] = EOS;
843         *fnum = sign * (whole + frac) * pow (10.0, expsign * exp);
844         if (*fnum < MIN_INT)
845             *inum = MIN_INT;
846         else if (*fnum > MAX_INT)
847             *inum = MAX_INT;
848         else
849             *inum = (int) *fnum;
850         return (TT_REAL);
851 }
852
853 static void 
854 eatline (void)
855 {
856         char term [2];
857
858         term[0] = NEWLINE;
859         term[1] = EOS;
860         skiptok (term);
861 }
862
863 static int 
864 type (          /* return type of ASCII character */
865     int c
866 )
867 {
868         if (isalpha(c) || c == UNDERLIN)
869             return (LETTER);
870         else if (isdigit(c))
871             return (DIGIT);
872         else
873             return (c);
874 }
875
876 /*----------------------------------------------------------------------*/
877 /*                                                                      */
878 /*  hash table routines. Kernighan & Ritchie                            */
879 /*                                                                      */
880 /*----------------------------------------------------------------------*/
881
882 /* inittable (table)
883  *      clear symbol table
884 */
885
886 static void 
887 inittable (SYMBOL *table[])
888 {
889         int i;
890
891         for (i = 0; i < HASHSIZE; i++)
892             table[i] = NULL;
893 }
894
895 /* freetable (table)
896  *      free all memory allocated to table, then clear table
897  */
898
899 static void 
900 freetable (SYMBOL *table[])
901 {
902         int i;
903         SYMBOL *p, *np;
904
905         for (i = 0; i < HASHSIZE; i++) {
906             np = table[i];
907             while (np != NULL) {
908                 p = np->next;
909                 free (np);
910                 np = p;
911             }
912         }
913         inittable (table);
914 }
915
916 static int 
917 hash (          /* form hash value of string s */
918     char *s
919 )
920 {
921         int hashval;
922
923         for (hashval = 0; *s != EOS; )
924             hashval += *s++;
925         return (hashval % HASHSIZE);
926 }
927
928 /* Look for s in hash table */
929 static SYMBOL *
930 lookup ( SYMBOL *table[], char *s )
931 {
932     SYMBOL *np;
933     SYMBOL *found = NULL;
934
935     for (np = table[hash(s)]; np != NULL; np = np->next)
936         if (strcasecmp(s, np->name) == 0) {
937             found = np;         /* found it */
938             break;
939         }
940
941     return (found);
942 }
943
944 static SYMBOL *
945 install (SYMBOL *table[], char *name, int def)
946 {
947     static char installerr[] = "install: out of memory";
948     SYMBOL *np;
949     int hashval;
950
951     if ((np = lookup (table, name)) == NULL) {  /* not found */
952         np = (SYMBOL *) malloc (sizeof(*np));
953         if (np == NULL) {
954             sys_error (ERR_SEVERE, installerr);
955             return (NULL);
956         }
957         if ((np->name = strdup(name)) == NULL) {
958             sys_error (ERR_SEVERE, installerr);
959             return (NULL);
960         }
961         str_lower (np->name);
962         np->code = def;
963         hashval = hash(np->name);
964         np->next = table[hashval];
965         table[hashval] = np;
966     } else                                      /* already there */
967         np->code = def;
968     return (np);
969 }
970
971 /*----------------------------------------------------------------------*/
972 /*                              POL OUTPUT                              */
973 /*----------------------------------------------------------------------*/
974
975 #define MAXFILE 8
976
977 static int currentf = -1;               /* pointer to current fp */
978 static FILE *filep[MAXFILE];            /* == NULL for string input */
979 static char *fname[MAXFILE];            /* pointer to filename */
980
981 static char inputline[MAXLINE];         /* current input line */
982 static int lineptr;                     /* current position in inputline */
983
984
985 //----------------------------------------------------------------------
986 //                              POL INPUT                               
987 //----------------------------------------------------------------------
988
989 #define BUFSIZE 100
990 static int bp = 0;              /* pointer to next free position */
991 static int buf[BUFSIZE];        /* pushed back input characters */
992
993 /* pol_usefile - set source of POL input
994  *
995  *    int source - source of input
996  *                 P_USE_STR  - have POL use strings as input
997  *                 P_USE_FILE - use file.  filename is in str
998  *
999 */
1000
1001 void 
1002 pol_usefile (int source, char *fn)
1003 {
1004         FILE *fp;
1005
1006         ++currentf;
1007         if (currentf >= MAXFILE) {
1008             --currentf;
1009             sys_error (ERR_SEVERE, "files nested too deeply");
1010             return;
1011         }
1012
1013         bp = 0;                         /* clear any pushed back input */
1014
1015         if (source == P_USE_STR) {
1016             filep[currentf] = NULL;
1017         } else if (source == P_USE_FILE) {
1018             if (fn == NULL || strlen(fn) == 0) {
1019                 fp = stdin;
1020             } else if ((fp = fopen(fn, "r")) == NULL) {
1021                 --currentf;
1022                 sys_error (ERR_SEVERE, "can't open file");
1023                 return;
1024             }
1025             filep[currentf] = fp;
1026             fname[currentf] = strdup (fn);
1027         }
1028 }
1029
1030 void pol_closefile(void)
1031 {
1032         if (currentf >= 0) {
1033             if (filep[currentf] != NULL)
1034                 fclose (filep[currentf]);
1035             --currentf;
1036         }
1037 }
1038
1039 /*-----------------------------*/
1040 /* Lowest Level Input Routines */
1041 /*-----------------------------*/
1042
1043
1044 int pol_lookchar(void)
1045 {
1046         int c;
1047
1048         c = pol_inchar();
1049         pol_ungetch (c);
1050         return (c);
1051 }
1052
1053 int pol_inchar(void)
1054 {
1055   int c = 0;
1056
1057   if (currentf < 0)
1058     return (EOF);
1059
1060   while (currentf >= 0 && (c = pol_getch(filep[currentf])) == EOF && filep[currentf] != NULL) {
1061     pol_closefile ();
1062   }
1063
1064   return (c);
1065 }
1066
1067 /*--------------------------------------------------------------*/
1068 /* getch - get a (possibly pushed back) character               */
1069 /*         if fp == NULL, then get character from inputline     */
1070 /*--------------------------------------------------------------*/
1071
1072 static int 
1073 pol_getch (FILE *fp)
1074 {
1075         int c;
1076
1077         if (bp > 0)
1078             return (buf[--bp]);
1079
1080         if (fp == NULL) {
1081             if ((c = inputline[lineptr]) == EOS)
1082                 return (EOF);
1083             else {
1084                 ++lineptr;
1085                 return (c);
1086             }
1087         } else
1088             c = fgetc(fp);
1089
1090         return (c);
1091 }
1092
1093 /* push character back on input */
1094 void 
1095 pol_ungetch (int c)
1096 {
1097         if (bp > BUFSIZE)
1098             sys_error (ERR_SEVERE, "too many characters pushed back [pol_ungetch]");
1099         else
1100             buf[bp++] = c;
1101 }
1102
1103
1104 int 
1105 get_inputline (FILE *fp)
1106 {
1107         lineptr = 0;
1108         bp = 0;
1109         if (fgets (inputline, MAXLINE, fp) == NULL)
1110             return (EOF);
1111         else
1112             return (OK);
1113 }
1114
1115 void 
1116 set_inputline (const char* const line)
1117 {
1118         lineptr = 0;
1119         bp = 0;
1120         strncpy (inputline, line, MAXLINE);
1121 }