1 /*****************************************************************************
4 ** POL - Problem Oriented Language
6 ** This is part of the CTSim program
7 ** Copyright (C) 1983-2000 Kevin Rosenberg
9 ** $Id: pol.cpp,v 1.6 2000/12/27 03:16:02 kevin Exp $
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.
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.
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 ******************************************************************************/
25 /*----------------------------------------------------------------------*/
31 #include "ctsupport.h"
38 const struct POL::KeywordCodeList POL::cmdlist[] = {
49 { "nl_eoc",PC_NL_EOC,},
50 { "nl_neoc", PC_NL_NEOC,},
52 { "troff", PC_TROFF,},
57 const int POL::NUMCMD = (sizeof(POL::cmdlist) / sizeof (struct POL::KeywordCodeList));
85 pol.skipchars[0] = EOS;
87 inittable (cmdtable); /* initialize symbol tables */
88 inittable (usertable);
89 inittable (skiptable);
91 for (unsigned int i = 0; i < NUMCMD; i++)
92 install (cmdtable, cmdlist[i].keyword, cmdlist[i].code);
94 token.ready = FALSE; /* no token read yet */
99 * char *w - word for pol to ignore and skip over in input
101 * tok() compares all tokens to words given to this routine. If it finds it,
102 * it will immediately read another token.
106 POL::skpword (char *w)
108 if (install (skiptable, w, 0) == NULL)
109 sys_error (ERR_SEVERE, "Too many skip words defined");
114 * skip all characters that appear in string s
117 POL::skpchar (char *s)
119 strncpy (pol.skipchars, s, MAXSKIPCHAR);
122 // installKeyword (str, code)
124 // char *str - token string to install
125 // int code - code to return for token
127 // tok() looks for these user defined tokens. If it finds one,
128 // it stores the tokens code in the token structure and returns TT_USERTOK
130 POL::installKeyword (char *str, int code)
132 if (install (usertable, str, code) == NULL)
134 sys_error (ERR_SEVERE, "Out of memory installing user tokens");
141 /* get_word - matches tokens on a letter by letter basis
143 * char *search - string to search for
144 * int nlet - maximum number of chars to search for match
148 POL::word (char *search, int nlet)
151 if (pol.trace == TRUE)
152 printf ("matching current token %s against word %s\n", token.tokstr, search);
154 if (strncasecmp (search, token.tokstr, nlet) == 0) {
161 /* usertok (str,code)
162 * see if current token is a user defined token set with install()
164 * char *str - token string as read from input
165 * int *code - returned code for user defined symbol
166 * return value - TRUE if current token has been user defined
167 * FALSE if current token is not user defined
170 POL::usertok (char *str, int *code)
174 if (pol.trace == TRUE)
175 printf ("checking if current token '%s' is user defined\n", token.tokstr);
177 if (token.type == TT_USERTOK) {
179 strcpy (str, token.tokstr);
188 /* isstring (s) - returns TRUE if current token is a string
190 * char *s - pointer to place to store token string
194 POL::string (char *str)
198 if (token.type == TT_STRING) {
199 strcpy (str, token.tokstr);
206 /* integer - test for an integer
208 * int *n: returned integer value
209 * int typecode = TT_INT if accept only integer values
210 * = TT_REAL if accept both real and integer values
211 * int boundcode= TRUE if force to lie between boundries
212 * = FALSE can take any value it likes
213 * int bb1: lower bound
214 * int bb2: upper bound
217 POL::integer (int *n, int typecode, int boundcode, int bb1, int bb2)
221 if (pol.trace == TRUE)
222 printf ("checking if current token %s is an integer\n", token.tokstr);
224 if (token.type == TT_INT || token.type == TT_REAL) {
225 if (boundcode == TRUE) {
226 if (token.inum < bb1)
228 else if (token.inum > bb2)
242 POL::readfloat (double *n, double typecode, double boundcode, double bb1, double bb2)
246 if (pol.trace == TRUE)
247 printf ("checking if current token %s is an floating point number\n", token.tokstr);
249 if (token.type == TT_INT || token.type == TT_REAL) {
250 if (boundcode == TRUE) {
251 if (token.fnum < bb1)
253 else if (token.fnum > bb2)
266 /*----------------------------------------------------------------------*/
267 /* skip() - skip over any token except for end of command sequence */
269 /* returns TRUE if succesful skip */
270 /* returns FALSE if already at end of command or EOF */
271 /*----------------------------------------------------------------------*/
276 char term[5]; /* string of characters not to skip */
279 if (pol.nl_eoc == TRUE) {
285 return (skiptok (term));
291 while (skip() == TRUE)
294 dumptok (&token); /* skip end of command token */
297 /* skiptok (term) - skip a token unless the first character of a token is
298 * in the string of terminators, term.
299 * char *term - string of termination characters, don't skip these characters
300 * skiptok() also does NOT skip TT_EOF
301 * returns (TRUE) if succesful skip of a token
302 * returns (FALSE) if didn't skip, read termination character or TT_EOF
306 POL::skiptok (char term[])
310 if (token.type == TT_EOF
311 || (token.type == TT_SPECLCHAR && strchr(term, token.tokstr[0]) != NULL))
320 POL::tok (struct token_st *token)
322 if (token->ready == FALSE)
325 if (token->type == TT_EOF && lookchar() != EOF)
327 return (token->type);
331 POL::dumptok (struct token_st *token)
333 if (token->ready == FALSE)
335 token->ready = FALSE;
339 POL::getpol_tok (struct token_st *token)
343 token->ready = FALSE;
347 if (token->type == TT_BLANK)
349 if (token->type == TT_SPECLCHAR) {
350 if (strchr(pol.skipchars, token->tokstr[0]) != NULL)
352 if (token->tokstr[0] == NEWLINE)
354 if (token->tokstr[0] == meta.cmd) {
358 if (token->tokstr[0] == meta.com) { /* skip comment */
362 if (token->tokstr[0] == meta.out) {
363 getescape(token->tokstr, meta.out, MAXTOK);
364 fputs (token->tokstr, stderr);
367 if (token->tokstr[0] == meta.con) { /* continuation across NEWLINE */
368 while (lookchar() == BLANK || lookchar() == TAB)
370 if (lookchar() == NEWLINE)
373 if (token->tokstr[0] == meta.ter) { /* get input from terminal */
374 usefile (P_USE_FILE, "");
377 return (token->type);
381 /* look for filler words */
383 if (lookup (skiptable, token->tokstr) != NULL) /* ignore words in skip table */
386 /* look for user defined symbols */
388 if ((sym = lookup (usertable, token->tokstr)) != NULL) {
389 token->type = TT_USERTOK;
390 token->code = sym->code;
394 if (pol.trace == TRUE)
395 printf ("Read token '%s', type = %d\n", token->tokstr, token->type);
397 return (token->type);
409 tt = getalpha (str, MAXTOK);
410 if (tt == TT_ERROR) {
411 sys_error (ERR_WARNING, "Error in POL parameter command");
415 if ((cmd = lookup (cmdtable,str)) == NULL) {
416 sys_error (ERR_WARNING, "POL: Unrecognized command %s", cmd);
433 usefile (P_USE_FILE, tok.tokstr);
445 printf("eoc = %c str = %c com = %c cmd = %c prg = %c\n",
446 meta.eoc, meta.str, meta.com, meta.cmd, meta.prg);
447 printf("con = %c out = %c ter = %c inb = %c\n",
448 meta.con, meta.out, meta.ter, meta.inb);
451 if (found == FALSE) {
453 if (tt != TT_SPECLCHAR) {
454 sys_error (ERR_SEVERE, "POL: Illegal command character");
459 meta.eoc = tok.tokstr[0];
462 meta.str = tok.tokstr[0];
465 meta.com = tok.tokstr[0];
468 meta.cmd = tok.tokstr[0];
471 meta.prg = tok.tokstr[0];
474 meta.con = tok.tokstr[0];
477 meta.out = tok.tokstr[0];
480 meta.ter = tok.tokstr[0];
483 meta.inb = tok.tokstr[0];
486 printf("command not implemented\n");
488 } /* switch (tok->type) */
489 } /* if (found == FALSE) */
490 reader(); /* clean up command */
491 } /* if legal command */
498 POL::gettok (TOKEN *tok)
503 int toksiz = MAXTOK; /* maximum length of token string */
505 while ((c = inchar()) == BLANK || c == TAB)
515 if (c == BLANK || c == TAB) { /* skip white space */
516 getblank(tok->tokstr, toksiz);
518 } else if (toktype == LETTER) {
519 toktype = getalpha (tok->tokstr, toksiz);
520 } else if (c == meta.str) { /* quoted string */
521 getquote (tok->tokstr, toksiz);
523 } else if (type(c) == DIGIT || c == PLUS || c == HYPHEN || c == PERIOD) {
524 toktype = getnumber (tok->tokstr, toksiz, &fnum, &inum);
525 } else if (c == EOF) {
526 tok->tokstr[0] = EOS;
531 tok->tokstr[1] = EOS;
532 toktype = TT_SPECLCHAR;
537 if (tok->type == TT_REAL || tok->type == TT_INT) {
550 POL::getblank (char *s, int toksiz)
554 while ((c = inchar()) == BLANK || c == TAB)
564 POL::getalpha (char *s, int toksiz)
566 int i, chartype, alphatype;
568 if (type(lookchar()) != LETTER) {
573 alphatype = TT_ALPHA;
574 for (i = 0; i < toksiz; i++) { /* get alphanumeric token */
576 chartype = type (s[i]);
577 if (chartype != LETTER && chartype != DIGIT)
579 if (chartype == DIGIT)
580 alphatype = TT_ALPNUM;
585 sys_error (ERR_SEVERE, "POL token too long.");
587 s[i] = EOS; /* terminate token */
592 /* getquote - get quoted string from file */
593 /* have already gotten delimiter in qs[0] */
595 POL::getquote (char *qs, int toksiz)
599 delim = inchar(); /* char = delimiter */
600 getescape(qs, delim, toksiz);
605 POL::getescape ( /* reads up to delim */
613 for (i = 0; (c = inchar()) != delim; i++) {
615 sys_error (ERR_WARNING, "Missing closing delimiter.");
619 sys_error (ERR_SEVERE, "string too long.");
624 sys_error (ERR_SEVERE, "end of file inside quotation");
626 } else if (c == BSLASH) { /* escape character */
628 c = inchar(); /* get escaped character */
636 POL::gettext (char *str, int lim)
640 while ((c = inchar()) == BLANK || c == TAB)
644 for (i = 0; i < lim && (c = inchar()) != EOF && c != NEWLINE; i++)
650 //----------------------------------------------
651 // Get a number for gettok()
652 //----------------------------------------------
657 char str[], /* string to return token in */
658 int strsize, /* maximum length of token string */
659 double *fnum, /* floating point value of number read */
660 int *inum /* integer value of number read */
664 double sign, whole, frac, powerof10, exp, expsign;
668 isSigned = FALSE; /* TRUE if number prefixed by '+' or '-' */
678 } else if (c == PLUS) {
682 } else if (c == PERIOD) {
683 if (type(lookchar()) != DIGIT) {
686 return (TT_SPECLCHAR);
689 } else if (type(c) != DIGIT) {
695 if (isSigned == TRUE) {
698 inchar(); /* get period */
699 c = lookchar(); /* look at character past period */
700 ungetch (PERIOD); /* put back period */
701 if (type(c) != DIGIT) {
703 return (TT_SPECLCHAR);
705 } else if (type (c) != DIGIT) {
707 return (TT_SPECLCHAR);
712 while (type(c = inchar()) == DIGIT) {
715 whole = 10.0 * whole + (c - '0');
717 ungetch (c); /* put back non-numeric character */
719 if (c != PERIOD && tolower(c) != 'e') {
721 *fnum = whole * sign;
724 else if (*fnum > MAX_INT)
731 if (lookchar() == PERIOD) {
740 while (type(c = inchar()) == DIGIT) {
743 frac += (double) (c - '0') / powerof10;
751 if (tolower(c) != 'e')
756 if ((c = inchar()) == PLUS) {
760 } else if (c == HYPHEN) {
764 } else if (type(c) != DIGIT) {
765 --sp; /* erase 'e' */
773 while (type(c = inchar()) == DIGIT) {
776 exp = 10 * exp + (c - '0');
783 *fnum = sign * (whole + frac) * pow (10.0, expsign * exp);
786 else if (*fnum > MAX_INT)
803 // return type of ASCII character
807 if (isalpha(c) || c == UNDERLIN)
815 /*----------------------------------------------------------------------*/
817 /* hash table routines. Kernighan & Ritchie */
819 /*----------------------------------------------------------------------*/
826 POL::inittable (SYMBOL *table[])
830 for (i = 0; i < HASHSIZE; i++)
835 * free all memory allocated to table, then clear table
839 POL::freetable (SYMBOL *table[])
844 for (i = 0; i < HASHSIZE; i++) {
855 // form hash value of string s
861 for (hashval = 0; *s != EOS; )
863 return (hashval % HASHSIZE);
866 /* Look for s in hash table */
868 POL::lookup ( SYMBOL *table[], char *s )
871 SYMBOL *found = NULL;
873 for (np = table[hash(s)]; np != NULL; np = np->next)
874 if (strcasecmp(s, np->name) == 0) {
875 found = np; /* found it */
883 POL::install (SYMBOL *table[], char *name, int def)
885 static char installerr[] = "install: out of memory";
889 if ((np = lookup (table, name)) == NULL) { /* not found */
890 np = (SYMBOL *) malloc (sizeof(*np));
892 sys_error (ERR_SEVERE, installerr);
895 if ((np->name = strdup(name)) == NULL) {
896 sys_error (ERR_SEVERE, installerr);
899 str_lower (np->name);
901 hashval = hash(np->name);
902 np->next = table[hashval];
904 } else /* already there */
909 //----------------------------------------------------------------------
911 //----------------------------------------------------------------------
914 /* usefile - set source of POL input
916 * int source - source of input
917 * P_USE_STR - have POL use strings as input
918 * P_USE_FILE - use file. filename is in str
923 POL::usefile (int source, char *fn)
928 if (currentf >= MAXFILE) {
930 sys_error (ERR_SEVERE, "files nested too deeply");
934 bp = 0; /* clear any pushed back input */
936 if (source == P_USE_STR) {
937 filep[currentf] = NULL;
938 } else if (source == P_USE_FILE) {
939 if (fn == NULL || strlen(fn) == 0) {
941 } else if ((fp = fopen(fn, "r")) == NULL) {
943 sys_error (ERR_SEVERE, "can't open file");
946 filep[currentf] = fp;
947 fname[currentf] = strdup (fn);
955 if (filep[currentf] != NULL)
956 fclose (filep[currentf]);
961 /*-----------------------------*/
962 /* Lowest Level Input Routines */
963 /*-----------------------------*/
984 while (currentf >= 0 && (c = getch(filep[currentf])) == EOF && filep[currentf] != NULL) {
991 /*--------------------------------------------------------------*/
992 /* getch - get a (possibly pushed back) character */
993 /* if fp == NULL, then get character from inputline */
994 /*--------------------------------------------------------------*/
997 POL::getch (FILE *fp)
1005 if ((c = inputline[lineptr]) == EOS)
1017 /* push character back on input */
1019 POL::ungetch (int c)
1022 sys_error (ERR_SEVERE, "too many characters pushed back [ungetch]");
1029 POL::get_inputline (FILE *fp)
1033 if (fgets (inputline, MAXLINE, fp) == NULL)
1040 POL::set_inputline (const char* const line)
1044 strncpy (inputline, line, MAXLINE);