📄 parse.c
字号:
/**********Copyright 1990 Regents of the University of California. All rights reserved.Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group**********//* * A simple operator-precedence parser for algebraic expressions. * This also handles relational and logical expressions. */#include "spice.h"#include "util.h"#include "cpdefs.h"#include "ftedefs.h"#include "fteparse.h"#include "ftedata.h"#include "ftecmath.h"#include "suffix.h"static bool checkvalid();static struct pnode *parse();static struct element *lexer();static struct pnode *mksnode();static struct pnode *mknnode();static struct pnode *mkfnode();static struct pnode *mkbnode();static struct pnode *mkunode();static struct pnode *makepnode();static int lasttoken = END, lasttype;static char *sbuf;struct pnode *ft_getpnames(wl, check) wordlist *wl; bool check;{ struct pnode *pn = NULL, *lpn = NULL, *p; char *xsbuf; char buf[BSIZE_SP], *thisone, *s; if (!wl) { fprintf(cp_err, "Warning: NULL arithmetic expression\n"); return (NULL); } lasttoken = END; xsbuf = sbuf = wl_flatten(wl); thisone = sbuf; while (*sbuf != '\0') { if (!(p = parse())) { tfree(xsbuf); return (NULL); } /* Now snag the name... Much trouble... */ while (isspace(*thisone)) thisone++; for (s = buf; thisone < sbuf; s++, thisone++) *s = *thisone; *s = '\0'; p->pn_name = copy(buf); if (pn) { lpn->pn_next = p; lpn = p; } else pn = lpn = p; } tfree(xsbuf); if (check) if (!checkvalid(pn)) return (NULL); return (pn);}/* See if there are any variables around which have length 0 and are * not named 'list'. There should really be another flag for this... */static boolcheckvalid(pn) struct pnode *pn;{ while (pn) { if (pn->pn_value) { if ((pn->pn_value->v_length == 0) && !eq(pn->pn_value->v_name, "list")) { if (eq(pn->pn_value->v_name, "all")) fprintf(cp_err, "Error: %s: no matching vectors.\n", pn->pn_value->v_name); else fprintf(cp_err, "Error: %s: no such vector.\n", pn->pn_value->v_name); return (false); } } else if (pn->pn_func || (pn->pn_op && (pn->pn_op->op_arity == 1))) { if (!checkvalid(pn->pn_left)) return (false); } else if (pn->pn_op && (pn->pn_op->op_arity == 2)) { if (!checkvalid(pn->pn_left)) return (false); if (!checkvalid(pn->pn_right)) return (false); } else fprintf(cp_err, "checkvalid: Internal Error: bad node\n"); pn = pn->pn_next; } return (true);}/* Everything else is a string or a number. Quoted strings are kept in * the form "string", and the lexer strips off the quotes... */static struct element *lexer(){ double *td; int j = 0; static struct element el; static struct element end = { END }; static char *specials = " \t%()-^+*,/|&<>~="; static bool bracflag = false; char *ss, *s; int atsign; if (bracflag) { bracflag = false; el.e_token = LPAREN; goto done; } el.e_token = END; while ((*sbuf == ' ') || (*sbuf == '\t')) sbuf++; if (*sbuf == '\0') goto done; switch (*sbuf) { case '-': if ((lasttoken == VALUE) || (lasttoken == RPAREN)) el.e_token = MINUS; else el.e_token = UMINUS; sbuf++; break; case '+': el.e_token = PLUS; sbuf++; break; case ',': el.e_token = COMMA; sbuf++; break; case '*': el.e_token = TIMES; sbuf++; break; case '%': el.e_token = MOD; sbuf++; break; case '/': el.e_token = DIVIDE; sbuf++; break; case '^': el.e_token = POWER; sbuf++; break; case '[': if (sbuf[1] == '[') { el.e_token = RANGE; sbuf += 2; } else { el.e_token = INDX; sbuf++; } bracflag = true; break; case '(': if (((lasttoken == VALUE) && ((lasttype == NUM))) || (lasttoken == RPAREN)) { el = end; goto done; } else { el.e_token = LPAREN; sbuf++; break; } case ']': el.e_token = RPAREN; if (sbuf[1] == ']') sbuf += 2; else sbuf++; break; case ')': el.e_token = RPAREN; sbuf++; break; case '=': el.e_token = EQ; sbuf++; break; case '>': case '<': for (j = 0; isspace(sbuf[j]); j++) ; /* The lexer makes <> into < > */ if (((sbuf[j] == '<') || (sbuf[j] == '>')) && (sbuf[0] != sbuf[j])) { /* Allow both <> and >< for NE. */ el.e_token = NE; sbuf += 2 + j; } else if (sbuf[1] == '=') { if (sbuf[0] == '>') el.e_token = GE; else el.e_token = LE; sbuf += 2; } else { if (sbuf[0] == '>') el.e_token = GT; else el.e_token = LT; sbuf++; } break; case '&': el.e_token = AND; sbuf++; break; case '|': el.e_token = OR; sbuf++; break; case '~': el.e_token = NOT; sbuf++; break; case '"': if ((lasttoken == VALUE) || (lasttoken == RPAREN)) { el = end; goto done; } el.e_token = VALUE; el.e_type = STRING; el.e_string = copy(++sbuf); for (s = el.e_string; *s && (*s != '"'); s++, sbuf++) ; *s = '\0'; sbuf++; break; } if (el.e_token != END) goto done; ss = sbuf; td = ft_numparse(&ss, false); if ((!ss || *ss != ':') && td) { if ((lasttoken == VALUE) || (lasttoken == RPAREN)) { el = end; goto done; } el.e_double = *td; el.e_type = NUM; el.e_token = VALUE; sbuf = ss; if (ft_parsedb) fprintf(stderr, "lexer: double %G\n", el.e_double); } else { /* First, let's check for eq, ne, and so on. */ if ((sbuf[0] == 'g') && (sbuf[1] == 't') && index(specials, sbuf[2])) { el.e_token = GT; sbuf += 2; } else if ((sbuf[0] == 'l') && (sbuf[1] == 't') && index(specials, sbuf[2])) { el.e_token = LT; sbuf += 2; } else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') && index(specials, sbuf[2])) { el.e_token = GE; sbuf += 2; } else if ((sbuf[0] == 'l') && (sbuf[1] == 'e') && index(specials, sbuf[2])) { el.e_token = LE; sbuf += 2; } else if ((sbuf[0] == 'n') && (sbuf[1] == 'e') && index(specials, sbuf[2])) { el.e_token = NE; sbuf += 2; } else if ((sbuf[0] == 'e') && (sbuf[1] == 'q') && index(specials, sbuf[2])) { el.e_token = EQ; sbuf += 2; } else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') && index(specials, sbuf[2])) { el.e_token = OR; sbuf += 2; } else if ((sbuf[0] == 'a') && (sbuf[1] == 'n') && (sbuf[2] == 'd') && index(specials, sbuf[3])) { el.e_token = AND; sbuf += 3; } else if ((sbuf[0] == 'n') && (sbuf[1] == 'o') && (sbuf[2] == 't') && index(specials, sbuf[3])) { el.e_token = NOT; sbuf += 3; } else { if ((lasttoken == VALUE) || (lasttoken == RPAREN)) { el = end; goto done; } el.e_string = copy(sbuf); /* XXXX !!!! */ /* It is bad how we have to recognise '[' -- sometimes * it is part of a word, when it defines a parameter * name, and otherwise it isn't. */ atsign = 0; for (s = el.e_string; *s && !index(specials, *s); s++, sbuf++) { if (*s == '@') atsign = 1; else if (*s == '[' && !atsign) break; } if (*s) *s = '\0'; el.e_type = STRING; el.e_token = VALUE; if (ft_parsedb) fprintf(stderr, "lexer: string %s\n", el.e_string); } }done: lasttoken = el.e_token; lasttype = el.e_type; if (ft_parsedb) fprintf(stderr, "lexer: token %d\n", el.e_token); return (&el);}/* The operator-precedence parser. */#define G 1 /* Greater than. */#define L 2 /* Less than. */#define E 3 /* Equal. */#define R 4 /* Error. */#define STACKSIZE 200static char prectable[23][23] = { /* $ + - * % / ^ u- ( ) , v = > < >= <= <> & | ~ IDX R *//* $ */ { R, L, L, L, L, L, L, L, L, R, L, L, L, L, L, L, L, L, L, L, L, L, L },/* + */ { G, G, G, L, L, L, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L },/* - */ { G, G, G, L, L, L, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L },/* * */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L },/* % */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L },/* / */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L },/* ^ */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L },/* u-*/ { G, G, G, G, G, G, G, G, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L },/* ( */ { R, L, L, L, L, L, L, L, L, E, L, L, L, L, L, L, L, L, L, L, L, L, L },/* ) */ { G, G, G, G, G, G, G, G, R, G, G, R, G, G, G, G, G, G, G, G, G, G, G },/* , */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, G, L, L },/* v */ { G, G, G, G, G, G, G, G, G, G, G, R, G, G, G, G, G, G, G, G, G, G, G },/* = */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L },/* > */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L },/* < */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L },/* >=*/ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L },/* <=*/ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L },/* <>*/ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L },/* & */ { G, L, L, L, L, L, L, L, L, G, L, L, L, L, L, L, L, L, G, G, L, L, L },/* | */ { G, L, L, L, L, L, L, L, L, G, L, L, L, L, L, L, L, L, L, G, L, L, L },/* ~ */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, G, L, L },/*INDX*/{ G, G, G, G, G, G, G, G, L, G, G, L, G, G, G, G, G, G, G, G, G, G, L },/*RAN*/ { G, G, G, G, G, G, G, G, L, G, G, L, G, G, G, G, G, G, G, G, G, G, G }} ;/* Return an expr. */static struct pnode *parse(){ struct element stack[STACKSIZE]; int sp = 0, st, i; struct element *top, *next; struct pnode *pn, *lpn, *rpn; char rel;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -