1 /*****************************************************************************
2 ** This is part of the CTSim program
3 ** Copyright (C) 1983-2000 Kevin Rosenberg
5 ** $Id: ezpol.cpp,v 1.1 2000/06/19 18:05:03 kevin Exp $
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License (version 2) as
9 ** published by the Free Software Foundation.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ******************************************************************************/
20 /*----------------------------------------------------------------------*/
21 /* POL - Problem Oriented Language */
23 /*----------------------------------------------------------------------*/
34 /* Tables words stored with install() & found with lookup() */
36 static SYMBOL *skiptable[HASHSIZE]; /* words to ignore and skip */
37 static SYMBOL *cmdtable[HASHSIZE]; /* pol parameter commands */
38 static SYMBOL *usertable[HASHSIZE]; /* user defined symbols */
40 static struct token_st token; /* current token */
42 static struct metachar {
43 char eoc; /* end of command character */
44 char str; /* string delimiter */
45 char com; /* comment character */
46 char cmd; /* pol parameter command character */
47 char prg; /* program load character */
48 char con; /* continuation across newline character */
49 char out; /* character that delimits output to terminal */
50 char ter; /* character indicates insertion of input from terminal */
51 char inb; /* input from graphics device */
54 /* current pol state */
56 static struct pol_st {
57 char skipchars[MAXSKIPCHAR]; /* characters to skip */
58 int nl_eoc; /* TRUE if newline character ends a command */
59 int trace; /* TRUE if trace is on */
67 /* internal codes for pol commands */
85 static struct key cmdlist[] = {
96 { "nl_eoc",PC_NL_EOC,},
97 { "nl_neoc", PC_NL_NEOC,},
99 { "troff", PC_TROFF,},
104 #define NUMCMD (sizeof(cmdlist) / sizeof (struct key))
106 static int ignorecase = TRUE;
108 static int skiptok(char term[]);
109 static int pol_tok(struct token_st *token);
110 static void dumptok(struct token_st *token);
113 static int getpol_tok(struct token_st *token);
114 static int getcmd(void);
115 static int gettok (TOKEN *tok);
116 static void getblank(char *s, int toksiz);
117 static int getalpha(char *s, int toksiz);
118 static void getquote(char *qs, int toksiz);
119 static void getescape(char *s, int delim, int toksiz);
120 static int getnumber (char str[], int strsize, double *fnum, int *inum);
121 static void eatline(void);
122 static int type(int c);
123 static void inittable(SYMBOL *table[]);
124 static void freetable(SYMBOL *table[]);
125 static int hash(char *s);
126 static SYMBOL *lookup(SYMBOL *table[], char *s);
127 static SYMBOL *install(SYMBOL *table[], char *s, int def);
128 static void outch(int c);
129 static void inc_line(void);
130 static int getlinect(void);
131 static void setlinect(int n);
132 static void synerr(char *msg);
133 static int pol_getch(FILE *fp);
134 static void ungets(char *s);
146 meta.con = AMPERSAND;
152 pol.skipchars[0] = EOS;
154 inittable (cmdtable); /* initialize symbol tables */
155 inittable (usertable);
156 inittable (skiptable);
158 for (i = 0; i < NUMCMD; i++)
159 install (cmdtable, cmdlist[i].keyword, cmdlist[i].code);
161 token.ready = FALSE; /* no token read yet */
166 * char *w - word for pol to ignore and skip over in input
168 * pol_tok() compares all tokens to words given to this routine. If it finds it,
169 * it will immediately read another token.
173 pol_skpword (char *w)
175 if (install (skiptable, w, 0) == NULL)
176 synerr ("Too many skip words defined");
181 * skip all characters that appear in string s
184 pol_skpchar (char *s)
186 strncpy (pol.skipchars, s, MAXSKIPCHAR);
189 /* pol_install (str, code)
191 * char *str - token string to install
192 * int code - code to return for token
194 * pol_tok() looks for these user defined tokens. If it finds one,
195 * it stores the tokens code in the token structure and returns TT_USERTOK
198 pol_install (char *str, int code)
200 if (install (usertable, str, code) == NULL)
202 synerr ("Out ot memory installing user tokens");
209 /* get_word - matches tokens on a letter by letter basis
211 * char *search - string to search for
212 * int nlet - maximum number of chars to search for match
216 pol_word (char *search, int nlet)
219 if (pol.trace == TRUE)
220 printf ("matching current token %s against word %s\n", token.tokstr, search);
222 if (strncasecmp (search, token.tokstr, nlet) == 0) {
229 /* pol_usertok (str,code)
230 * see if current token is a user defined token set with pol_install()
232 * char *str - token string as read from input
233 * int *code - returned code for user defined symbol
234 * return value - TRUE if current token has been user defined
235 * FALSE if current token is not user defined
238 pol_usertok (char *str, int *code)
242 if (pol.trace == TRUE)
243 printf ("checking if current token '%s' is user defined\n", token.tokstr);
245 if (token.type == TT_USERTOK) {
247 strcpy (str, token.tokstr);
256 /* isstring (s) - returns TRUE if current token is a string
258 * char *s - pointer to place to store token string
262 pol_string (char *str)
266 if (token.type == TT_STRING) {
267 strcpy (str, token.tokstr);
274 /* pol_integer - test for an integer
276 * int *n: returned integer value
277 * int typecode = TT_INT if accept only integer values
278 * = TT_REAL if accept both real and integer values
279 * int boundcode= TRUE if force to lie between boundries
280 * = FALSE can take any value it likes
281 * int bb1: lower bound
282 * int bb2: upper bound
285 pol_integer (int *n, int typecode, int boundcode, int bb1, int bb2)
289 if (pol.trace == TRUE)
290 printf ("checking if current token %s is an integer\n", token.tokstr);
292 if (token.type == TT_INT || token.type == TT_REAL) {
293 if (boundcode == TRUE) {
294 if (token.inum < bb1)
296 else if (token.inum > bb2)
310 pol_float (double *n, double typecode, double boundcode, double bb1, double bb2)
314 if (pol.trace == TRUE)
315 printf ("checking if current token %s is an floating point number\n", token.tokstr);
317 if (token.type == TT_INT || token.type == TT_REAL) {
318 if (boundcode == TRUE) {
319 if (token.fnum < bb1)
321 else if (token.fnum > bb2)
334 /*----------------------------------------------------------------------*/
335 /* pol_skip() - skip over any token except for end of command sequence */
337 /* returns TRUE if succesful skip */
338 /* returns FALSE if already at end of command or EOF */
339 /*----------------------------------------------------------------------*/
343 char term[5]; /* string of characters not to skip */
346 if (pol.nl_eoc == TRUE) {
352 return (skiptok (term));
355 void pol_reader(void)
357 while (pol_skip() == TRUE)
360 dumptok (&token); /* skip end of command token */
363 /* skiptok (term) - skip a token unless the first character of a token is
364 * in the string of terminators, term.
365 * char *term - string of termination characters, don't skip these characters
366 * skiptok() also does NOT skip TT_EOF
367 * returns (TRUE) if succesful skip of a token
368 * returns (FALSE) if didn't skip, read termination character or TT_EOF
372 skiptok (char term[])
376 if (token.type == TT_EOF
377 || (token.type == TT_SPECLCHAR && strchr(term, token.tokstr[0]) != NULL))
386 pol_tok (struct token_st *token)
388 if (token->ready == FALSE)
391 if (token->type == TT_EOF && pol_lookchar() != EOF)
393 return (token->type);
397 dumptok (struct token_st *token)
399 if (token->ready == FALSE)
401 token->ready = FALSE;
405 getpol_tok (struct token_st *token)
409 token->ready = FALSE;
413 if (token->type == TT_BLANK)
415 if (token->type == TT_SPECLCHAR) {
416 if (strchr(pol.skipchars, token->tokstr[0]) != NULL)
418 if (token->tokstr[0] == NEWLINE)
420 if (token->tokstr[0] == meta.cmd) {
424 if (token->tokstr[0] == meta.com) { /* skip comment */
428 if (token->tokstr[0] == meta.out) {
429 getescape(token->tokstr, meta.out, MAXTOK);
430 fputs (token->tokstr, stderr);
433 if (token->tokstr[0] == meta.con) { /* continuation across NEWLINE */
434 while (pol_lookchar() == BLANK || pol_lookchar() == TAB)
436 if (pol_lookchar() == NEWLINE)
439 if (token->tokstr[0] == meta.ter) { /* get input from terminal */
440 pol_usefile (P_USE_FILE, "");
443 return (token->type);
447 /* look for filler words */
449 if (lookup (skiptable, token->tokstr) != NULL) /* ignore words in skip table */
452 /* look for user defined symbols */
454 if ((sym = lookup (usertable, token->tokstr)) != NULL) {
455 token->type = TT_USERTOK;
456 token->code = sym->code;
460 if (pol.trace == TRUE)
461 printf ("Read token '%s', type = %d\n", token->tokstr, token->type);
463 return (token->type);
467 static int getcmd(void)
474 tt = getalpha (str, MAXTOK);
475 if (tt == TT_ERROR) {
476 synerr ("error in pol parameter command");
480 if ((cmd = lookup (cmdtable,str)) == NULL) {
481 synerr ("unrecognized command");
498 pol_usefile (P_USE_FILE, tok.tokstr);
510 printf("eoc = %c str = %c com = %c cmd = %c prg = %c\n",
511 meta.eoc, meta.str, meta.com, meta.cmd, meta.prg);
512 printf("con = %c out = %c ter = %c inb = %c\n",
513 meta.con, meta.out, meta.ter, meta.inb);
516 if (found == FALSE) {
518 if (tt != TT_SPECLCHAR) {
519 synerr("illegal command character");
524 meta.eoc = tok.tokstr[0];
527 meta.str = tok.tokstr[0];
530 meta.com = tok.tokstr[0];
533 meta.cmd = tok.tokstr[0];
536 meta.prg = tok.tokstr[0];
539 meta.con = tok.tokstr[0];
542 meta.out = tok.tokstr[0];
545 meta.ter = tok.tokstr[0];
548 meta.inb = tok.tokstr[0];
551 printf("command not implemented\n");
553 } /* switch (tok->type) */
554 } /* if (found == FALSE) */
555 pol_reader(); /* clean up command */
556 } /* if legal command */
568 int toksiz = MAXTOK; /* maximum length of token string */
570 while ((c = pol_inchar()) == BLANK || c == TAB)
580 if (c == BLANK || c == TAB) { /* skip white space */
581 getblank(tok->tokstr, toksiz);
583 } else if (toktype == LETTER) {
584 toktype = getalpha (tok->tokstr, toksiz);
585 } else if (c == meta.str) { /* quoted string */
586 getquote (tok->tokstr, toksiz);
588 } else if (type(c) == DIGIT || c == PLUS || c == HYPHEN || c == PERIOD) {
589 toktype = getnumber (tok->tokstr, toksiz, &fnum, &inum);
590 } else if (c == EOF) {
591 tok->tokstr[0] = EOS;
596 tok->tokstr[1] = EOS;
597 toktype = TT_SPECLCHAR;
602 if (tok->type == TT_REAL || tok->type == TT_INT) {
615 getblank (char *s, int toksiz)
619 while ((c = pol_inchar()) == BLANK || c == TAB)
629 getalpha (char *s, int toksiz)
631 int i, chartype, alphatype;
633 if (type(pol_lookchar()) != LETTER) {
638 alphatype = TT_ALPHA;
639 for (i = 0; i < toksiz; i++) { /* get alphanumeric token */
641 chartype = type (s[i]);
642 if (chartype != LETTER && chartype != DIGIT)
644 if (chartype == DIGIT)
645 alphatype = TT_ALPNUM;
650 synerr("token too long.");
652 s[i] = EOS; /* terminate token */
657 /* getquote - get quoted string from file */
658 /* have already gotten delimiter in qs[0] */
660 getquote (char *qs, int toksiz)
664 delim = pol_inchar(); /* char = delimiter */
665 getescape(qs, delim, toksiz);
670 getescape ( /* reads up to delim */
678 for (i = 0; (c = pol_inchar()) != delim; i++) {
680 synerr ("Missing closing delimiter.");
684 synerr("string too long.");
689 synerr("end of file inside quotation");
691 } else if (c == BSLASH) { /* escape character */
693 c = pol_inchar(); /* get escaped character */
701 gettext (char *str, int lim)
705 while ((c = pol_inchar()) == BLANK || c == TAB)
709 for (i = 0; i < lim && (c = pol_inchar()) != EOF && c != NEWLINE; i++)
715 /*----------------------------------------------*/
716 /* Get a number for gettok() */
717 /*----------------------------------------------*/
721 char str[], /* string to return token in */
722 int strsize, /* maximum length of token string */
723 double *fnum, /* floating point value of number read */
724 int *inum /* integer value of number read */
728 double sign, whole, frac, powerof10, exp, expsign;
732 isSigned = FALSE; /* TRUE if number prefixed by '+' or '-' */
742 } else if (c == PLUS) {
746 } else if (c == PERIOD) {
747 if (type(pol_lookchar()) != DIGIT) {
750 return (TT_SPECLCHAR);
752 pol_ungetch (PERIOD);
753 } else if (type(c) != DIGIT) {
759 if (isSigned == TRUE) {
762 pol_inchar(); /* get period */
763 c = pol_lookchar(); /* look at character past period */
764 pol_ungetch (PERIOD); /* put back period */
765 if (type(c) != DIGIT) {
767 return (TT_SPECLCHAR);
769 } else if (type (c) != DIGIT) {
771 return (TT_SPECLCHAR);
776 while (type(c = pol_inchar()) == DIGIT) {
779 whole = 10.0 * whole + (c - '0');
781 pol_ungetch (c); /* put back non-numeric character */
783 if (c != PERIOD && tolower(c) != 'e') {
785 *fnum = whole * sign;
788 else if (*fnum > MAX_INT)
795 if (pol_lookchar() == PERIOD) {
804 while (type(c = pol_inchar()) == DIGIT) {
807 frac += (double) (c - '0') / powerof10;
815 if (tolower(c) != 'e')
820 if ((c = pol_inchar()) == PLUS) {
824 } else if (c == HYPHEN) {
828 } else if (type(c) != DIGIT) {
829 --sp; /* erase 'e' */
837 while (type(c = pol_inchar()) == DIGIT) {
840 exp = 10 * exp + (c - '0');
847 *fnum = sign * (whole + frac) * pow (10.0, expsign * exp);
850 else if (*fnum > MAX_INT)
868 type ( /* return type of ASCII character */
872 if (isalpha(c) || c == UNDERLIN)
880 /*----------------------------------------------------------------------*/
882 /* hash table routines. Kernighan & Ritchie */
884 /*----------------------------------------------------------------------*/
891 inittable (SYMBOL *table[])
895 for (i = 0; i < HASHSIZE; i++)
900 * free all memory allocated to table, then clear table
904 freetable (SYMBOL *table[])
909 for (i = 0; i < HASHSIZE; i++) {
921 hash ( /* form hash value of string s */
927 for (hashval = 0; *s != EOS; )
929 return (hashval % HASHSIZE);
932 /* Look for s in hash table */
934 lookup ( SYMBOL *table[], char *s )
937 SYMBOL *found = NULL;
939 for (np = table[hash(s)]; np != NULL; np = np->next)
940 if (strcasecmp(s, np->name) == 0) {
941 found = np; /* found it */
949 install (SYMBOL *table[], char *name, int def)
951 static char installerr[] = "install: out of memory";
955 if ((np = lookup (table, name)) == NULL) { /* not found */
956 np = (SYMBOL *) malloc (sizeof(*np));
961 if ((np->name = strdup(name)) == NULL) {
965 str_lower (np->name);
967 hashval = hash(np->name);
968 np->next = table[hashval];
970 } else /* already there */
975 /*----------------------------------------------------------------------*/
977 /*----------------------------------------------------------------------*/
981 static int currentf = -1; /* pointer to current fp */
982 static FILE *filep[MAXFILE]; /* == NULL for string input */
983 static char *fname[MAXFILE]; /* pointer to filename */
984 static int linect[MAXFILE]; /* line count in file */
986 static char inputline[MAXLINE]; /* current input line */
987 static int lineptr; /* current position in inputline */
996 static void inc_line(void)
1002 static int getlinect(void)
1004 return (linect[currentf]);
1011 linect[currentf] = n;
1017 fputs (fname[currentf], stderr);
1018 fprintf(stderr, "%d", linect[currentf]);
1019 fputc (COLON, stderr);
1020 fputs (msg, stderr);
1021 fputc (NEWLINE, stderr);
1024 /*----------------------------------------------------------------------*/
1026 /*----------------------------------------------------------------------*/
1029 static int bp = 0; /* pointer to next free position */
1030 static int buf[BUFSIZE]; /* pushed back input characters */
1032 /* pol_usefile - set source of POL input
1034 * int source - source of input
1035 * P_USE_STR - have POL use strings as input
1036 * P_USE_FILE - use file. filename is in str
1041 pol_usefile (int source, char *fn)
1046 if (currentf >= MAXFILE) {
1048 synerr ("files nested too deeply");
1052 bp = 0; /* clear any pushed back input */
1054 if (source == P_USE_STR) {
1055 filep[currentf] = NULL;
1056 linect[currentf] = 1;
1057 } else if (source == P_USE_FILE) {
1058 if (fn == NULL || strlen(fn) == 0) {
1060 } else if ((fp = fopen(fn, "r")) == NULL) {
1062 synerr ("can't open file");
1065 filep[currentf] = fp;
1066 linect[currentf] = 1;
1067 fname[currentf] = strdup (fn);
1071 void pol_closefile(void)
1073 if (currentf >= 0) {
1074 if (filep[currentf] != NULL)
1075 fclose (filep[currentf]);
1080 /*-----------------------------*/
1081 /* Lowest Level Input Routines */
1082 /*-----------------------------*/
1085 int pol_lookchar(void)
1094 int pol_inchar(void)
1101 while (currentf >= 0 && (c = pol_getch(filep[currentf])) == EOF && filep[currentf] != NULL) {
1108 /*--------------------------------------------------------------*/
1109 /* getch - get a (possibly pushed back) character */
1110 /* if fp == NULL, then get character from inputline */
1111 /*--------------------------------------------------------------*/
1114 pol_getch (FILE *fp)
1122 if ((c = inputline[lineptr]) == EOS)
1134 /* push character back on input */
1139 sys_error (ERR_SEVERE, "too many characters pushed back [pol_ungetch]");
1145 /* push back string onto input */
1151 for (i = strlen(s) - 1; i >= 0; i--)
1156 get_inputline (FILE *fp)
1160 if (fgets (inputline, MAXLINE, fp) == NULL)
1167 set_inputline (char *line)
1171 strncpy (inputline, line, MAXLINE);