1 /*****************************************************************************
4 ** POL - Problem Oriented Language
6 ** This is part of the CTSim program
7 ** Copyright (c) 1983-2009 Kevin Rosenberg
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License (version 2) as
11 ** published by the Free Software Foundation.
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ******************************************************************************/
27 #include "ctsupport.h"
31 const struct POL::KeywordCodeList POL::cmdlist[] = {
42 { "nl_eoc",PC_NL_EOC,},
43 { "nl_neoc", PC_NL_NEOC,},
45 { "troff", PC_TROFF,},
50 const unsigned int POL::NUMCMD = (sizeof(POL::cmdlist) / sizeof (struct POL::KeywordCodeList));
77 m_bNewlineIsEOC = true;
78 m_szSkipChars[0] = EOS;
81 for (unsigned int i = 0; i < NUMCMD; i++)
82 cmdtable.installKeywordCode (cmdlist[i].keyword, cmdlist[i].code);
84 token.ready = false; // no token read yet
90 * char *w - word for pol to ignore and skip over in input
92 * tok() compares all tokens to words given to this routine. If it finds it,
93 * it will immediately read another token.
97 POL::addSkipWord (const char* const w)
99 skiptable.installKeywordCode (w, 0);
104 * skip all characters that appear in string s
107 POL::addSkipChar (int c)
109 int n = strlen (m_szSkipChars);
110 if (n < MAXSKIPCHAR) {
111 m_szSkipChars[n] = c;
112 m_szSkipChars[n+1] = 0;
116 // installKeyword (str, code)
118 // char *str - token string to install
119 // int code - code to return for token
121 // tok() looks for these user defined tokens. If it finds one,
122 // it stores the tokens code in the token structure and returns TT_USERTOK
124 POL::addKeyword (const char* const str, int code)
126 usertable.installKeywordCode (str, code);
129 /* get_word - matches tokens on a letter by letter basis
131 * char *search - string to search for
132 * int nlet - maximum number of chars to search for match
136 POL::readWord (const char *search, int nlet)
140 sys_error (ERR_TRACE, "POL matching current token %s against word %s\n", token.tokstr, search);
142 if (strncasecmp (search, token.tokstr, nlet) == 0) {
149 /* usertok (str,code)
150 * see if current token is a user defined token set with install()
152 * char *str - token string as read from input
153 * int *code - returned code for user defined symbol
154 * return value - true if current token has been user defined
155 * false if current token is not user defined
158 POL::readUserToken (char *str, int *code)
163 sys_error (ERR_TRACE, "POL checking if current token '%s' is user defined\n", token.tokstr);
165 if (token.type == TT_USERTOK) {
167 strcpy (str, token.tokstr);
176 /* isstring (s) - returns true if current token is a string
178 * char *s - pointer to place to store token string
182 POL::readString (char *str)
186 if (token.type == TT_STRING) {
187 strcpy (str, token.tokstr);
194 /* integer - test for an integer
196 * int *n: returned integer value
197 * int typecode = TT_INT if accept only integer values
198 * = TT_REAL if accept both real and integer values
199 * int boundcode= true if force to lie between boundries
200 * = false can take any value it likes
201 * int bb1: lower bound
202 * int bb2: upper bound
205 POL::readInteger (int *n, int typecode, bool boundcode, int bb1, int bb2)
210 sys_error (ERR_TRACE, "POL checking if current token %s is an integer\n", token.tokstr);
212 if (token.type == TT_INT || token.type == TT_REAL) {
214 if (token.inum < bb1)
216 else if (token.inum > bb2)
230 POL::readFloat (double *n, double typecode, bool boundcode, double bb1, double bb2)
235 sys_error (ERR_TRACE, "POL checking if current token %s is an floating point number\n", token.tokstr);
237 if (token.type == TT_INT || token.type == TT_REAL) {
239 if (token.fnum < bb1)
241 else if (token.fnum > bb2)
254 /*----------------------------------------------------------------------*/
255 /* skip() - skip over any token except for end of command sequence */
257 /* returns true if succesful skip */
258 /* returns false if already at end of command or EOF */
259 /*----------------------------------------------------------------------*/
264 char term[5]; /* string of characters not to skip */
267 if (m_bNewlineIsEOC) {
273 return (skipSingleToken (term));
282 dumptok (&token); /* skip end of command token */
285 /* skiptok (term) - skip a token unless the first character of a token is
286 * in the string of terminators, term.
287 * char *term - string of termination characters, don't skip these characters
288 * skiptok() also does NOT skip TT_EOF
289 * returns (true) if succesful skip of a token
290 * returns (false) if didn't skip, read termination character or TT_EOF
294 POL::skipSingleToken (char term[])
298 if (token.type == TT_EOF
299 || (token.type == TT_SPECLCHAR && strchr(term, token.tokstr[0]) != NULL))
308 POL::tok (struct token_st *token)
310 if (token->ready == false)
313 if (token->type == TT_EOF && lookchar() != EOF)
316 return (token->type);
320 POL::dumptok (struct token_st *token)
322 if (token->ready == false)
324 token->ready = false;
328 POL::getpol_tok (struct token_st *token)
330 KeywordCodeEntry* sym;
332 token->ready = false;
336 if (token->type == TT_BLANK)
338 if (token->type == TT_SPECLCHAR) {
339 if (strchr(m_szSkipChars, token->tokstr[0]) != NULL)
341 if (token->tokstr[0] == NEWLINE)
343 if (token->tokstr[0] == meta.cmd) {
347 if (token->tokstr[0] == meta.com) { /* skip comment */
351 if (token->tokstr[0] == meta.out) {
352 getescape(token->tokstr, meta.out, MAXTOK);
353 fputs (token->tokstr, stderr);
356 if (token->tokstr[0] == meta.con) { /* continuation across NEWLINE */
357 while (lookchar() == BLANK || lookchar() == TAB)
359 if (lookchar() == NEWLINE)
362 if (token->tokstr[0] == meta.ter) { /* get input from terminal */
363 usefile (P_USE_FILE, "");
366 return (token->type);
370 /* look for filler words */
372 if (skiptable.lookup (token->tokstr) != NULL) /* ignore words in skip table */
375 /* look for user defined symbols */
377 if ((sym = usertable.lookup (token->tokstr)) != NULL) {
378 token->type = TT_USERTOK;
379 token->code = sym->getCode();
384 sys_error (ERR_TRACE, "POL read token '%s', type = %d\n", token->tokstr, token->type);
386 return (token->type);
395 KeywordCodeEntry *cmd;
398 tt = getalpha (str, MAXTOK);
399 if (tt == TT_ERROR) {
400 sys_error (ERR_WARNING, "Error in POL parameter command");
404 if ((cmd = cmdtable.lookup (str)) == NULL) {
405 sys_error (ERR_WARNING, "POL: Unrecognized command %s", cmd);
410 switch (cmd->getCode()) {
422 usefile (P_USE_FILE, tok.tokstr);
426 m_bNewlineIsEOC = true;
430 m_bNewlineIsEOC = false;
434 printf("eoc = %c str = %c com = %c cmd = %c prg = %c\n",
435 meta.eoc, meta.str, meta.com, meta.cmd, meta.prg);
436 printf("con = %c out = %c ter = %c inb = %c\n",
437 meta.con, meta.out, meta.ter, meta.inb);
440 if (found == false) {
442 if (tt != TT_SPECLCHAR) {
443 sys_error (ERR_SEVERE, "POL: Illegal command character");
446 switch(cmd->getCode()) {
448 meta.eoc = tok.tokstr[0];
451 meta.str = tok.tokstr[0];
454 meta.com = tok.tokstr[0];
457 meta.cmd = tok.tokstr[0];
460 meta.prg = tok.tokstr[0];
463 meta.con = tok.tokstr[0];
466 meta.out = tok.tokstr[0];
469 meta.ter = tok.tokstr[0];
472 meta.inb = tok.tokstr[0];
475 printf("command not implemented\n");
477 } /* switch (tok->type) */
478 } /* if (found == false) */
479 reader(); /* clean up command */
480 } /* if legal command */
487 POL::gettok (TOKEN *tok)
492 int toksiz = MAXTOK; /* maximum length of token string */
494 while ((c = inchar()) == BLANK || c == TAB)
504 if (c == BLANK || c == TAB) { /* skip white space */
505 getblank(tok->tokstr, toksiz);
507 } else if (toktype == LETTER) {
508 toktype = getalpha (tok->tokstr, toksiz);
509 } else if (c == meta.str) { /* quoted string */
510 getquote (tok->tokstr, toksiz);
512 } else if (type(c) == DIGIT || c == PLUS || c == HYPHEN || c == PERIOD) {
513 toktype = getnumber (tok->tokstr, toksiz, &fnum, &inum);
514 } else if (c == EOF) {
515 tok->tokstr[0] = EOS;
520 tok->tokstr[1] = EOS;
521 toktype = TT_SPECLCHAR;
526 if (tok->type == TT_REAL || tok->type == TT_INT) {
539 POL::getblank (char *s, int toksiz)
543 while ((c = inchar()) == BLANK || c == TAB)
553 POL::getalpha (char *s, int toksiz)
555 int i, chartype, alphatype;
557 if (type(lookchar()) != LETTER) {
562 alphatype = TT_ALPHA;
563 for (i = 0; i < toksiz; i++) { /* get alphanumeric token */
565 chartype = type (s[i]);
566 if (chartype != LETTER && chartype != DIGIT)
568 if (chartype == DIGIT)
569 alphatype = TT_ALPNUM;
574 sys_error (ERR_SEVERE, "POL token too long.");
576 s[i] = EOS; /* terminate token */
581 /* getquote - get quoted string from file */
582 /* have already gotten delimiter in qs[0] */
584 POL::getquote (char *qs, int toksiz)
588 delim = inchar(); /* char = delimiter */
589 getescape(qs, delim, toksiz);
594 POL::getescape ( /* reads up to delim */
602 for (i = 0; (c = inchar()) != delim; i++) {
604 sys_error (ERR_WARNING, "Missing closing delimiter.");
608 sys_error (ERR_SEVERE, "string too long.");
613 sys_error (ERR_SEVERE, "end of file inside quotation");
615 } else if (c == BSLASH) { /* escape character */
617 c = inchar(); /* get escaped character */
626 POL::readText (char *str, int lim)
629 while ((c = inchar()) == BLANK || c == TAB)
638 for (i = 0; i < lim && (c = inchar()) != EOF && c != NEWLINE; i++)
646 //----------------------------------------------
647 // Get a number for gettok()
648 //----------------------------------------------
653 char str[], /* string to return token in */
654 int strsize, /* maximum length of token string */
655 double *fnum, /* floating point value of number read */
656 int *inum /* integer value of number read */
661 bool isSigned = false; /* true if number prefixed by '+' or '-' */
671 } else if (c == PLUS) {
675 } else if (c == PERIOD) {
676 if (type(lookchar()) != DIGIT) {
679 return (TT_SPECLCHAR);
682 } else if (type(c) != DIGIT) {
691 inchar(); /* get period */
692 c = lookchar(); /* look at character past period */
693 ungetch (PERIOD); /* put back period */
694 if (type(c) != DIGIT) {
696 return (TT_SPECLCHAR);
698 } else if (type (c) != DIGIT) {
700 return (TT_SPECLCHAR);
705 while (type(c = inchar()) == DIGIT) {
708 whole = 10.0 * whole + (c - '0');
710 ungetch (c); /* put back non-numeric character */
712 if (c != PERIOD && tolower(c) != 'e') {
714 *fnum = whole * sign;
717 else if (*fnum > MAX_INT)
724 if (lookchar() == PERIOD) {
731 double powerof10 = 10.0;
733 while (type(c = inchar()) == DIGIT) {
736 frac += (double) (c - '0') / powerof10;
742 double expsign = 1.0;
744 if (tolower(c) != 'e')
749 if ((c = inchar()) == PLUS) {
753 } else if (c == HYPHEN) {
757 } else if (type(c) != DIGIT) {
758 --sp; /* erase 'e' */
766 while (type(c = inchar()) == DIGIT) {
769 exp = 10 * exp + (c - '0');
776 *fnum = sign * (whole + frac) * pow (10.0, expsign * exp);
779 else if (*fnum > MAX_INT)
793 skipSingleToken (term);
796 // return type of ASCII character
800 if (isalpha(c) || c == UNDERLIN)
809 //----------------------------------------------------------------------
811 //----------------------------------------------------------------------
814 /* usefile - set source of POL input
816 * int source - source of input
817 * P_USE_STR - have POL use strings as input
818 * P_USE_FILE - use file. filename is in str
823 POL::usefile (int source, const char *fn)
828 if (currentf >= MAXFILE) {
830 sys_error (ERR_SEVERE, "files nested too deeply");
834 while (! m_stackPushBackInput.empty())
835 m_stackPushBackInput.pop();
837 if (source == P_USE_STR) {
838 filep[currentf] = NULL;
839 } else if (source == P_USE_FILE) {
840 if (fn == NULL || strlen(fn) == 0) {
842 } else if ((fp = fopen(fn, "r")) == NULL) {
844 sys_error (ERR_SEVERE, "can't open file");
847 filep[currentf] = fp;
848 fname[currentf] = strdup (fn);
856 if (filep[currentf] != NULL)
857 fclose (filep[currentf]);
862 /*-----------------------------*/
863 /* Lowest Level Input Routines */
864 /*-----------------------------*/
885 while (currentf >= 0 && (c = getch(filep[currentf])) == EOF && filep[currentf] != NULL) {
892 /*--------------------------------------------------------------*/
893 /* getch - get a (possibly pushed back) character */
894 /* if fp == NULL, then get character from inputline */
895 /*--------------------------------------------------------------*/
898 POL::getch (FILE *fp)
901 if (m_stackPushBackInput.size() > 0) {
902 c = m_stackPushBackInput.top();
903 m_stackPushBackInput.pop();
908 if ((c = inputline[lineptr]) == EOS)
920 // push character back on input
924 m_stackPushBackInput.push (c);
929 POL::get_inputline (FILE *fp)
931 while (! m_stackPushBackInput.empty())
932 m_stackPushBackInput.pop();
935 if (fgets (inputline, MAXLINE, fp) == NULL)
942 POL::set_inputline (const char* const line)
944 while (! m_stackPushBackInput.empty())
945 m_stackPushBackInput.pop();
947 strncpy (inputline, line, MAXLINE);