new parser for B source

This commit is contained in:
h_vogt 2010-02-28 16:00:40 +00:00
parent 4068f498c6
commit 75d891e4c0
10 changed files with 2183 additions and 238 deletions

View File

@ -1,3 +1,8 @@
2010-02-28 Holger Vogt
* inpcom.c, xpressn.c, inpptree.h, spicelib/parser/makefile.am, inpptree.c,
ptfuncs.c, inpptree-parser.y: replace parser for B source with BISON generated one.
Patch 2 from R. Larice
2010-02-27 Holger Vogt
* command.c, gnuplot.c, gnuplot.h, com_gnuplot.c, com_gnuplot.h, plotit.c:
new command 'wrdata file vecs' for simple tabular printout of data

View File

@ -1026,6 +1026,7 @@ inp_fix_ternary_operator( struct line *start_card )
if (found_control) continue;
if ( *line == 'B' || *line == 'b' ) continue;
if ( *line == '*' ) continue;
if ( strstr( line, "?" ) && strstr( line, ":" ) ) {
card->li_line = inp_fix_ternary_operator_str( line );

View File

@ -1825,6 +1825,7 @@ nupa_substitute (tdico * dico, char *s, char *r, unsigned char err)
{
i++;
c = s[i - 1];
if (c == Pspice)
{ /* try pspice expression syntax */
k = i;
@ -1860,7 +1861,13 @@ nupa_substitute (tdico * dico, char *s, char *r, unsigned char err)
}
else if (c == Intro)
{
i++;
/* skip "&&" which may occur in B source */
if ((i + 1 < ls) && (s[i] == Intro)) {
i++;
continue;
}
i++;
while ((i < ls) && (s[i - 1] <= ' '))
i++;

View File

@ -98,6 +98,12 @@ typedef struct INPparseNode {
#define PTF_USTEP2 21
#define PTF_PWL 22
#define PTF_PWL_DERIVATIVE 23
#define PTF_EQ0 24
#define PTF_NE0 25
#define PTF_GT0 26
#define PTF_LT0 27
#define PTF_GE0 28
#define PTF_LE0 29
/* The following things are used by the parser -- these are the token types the
@ -168,6 +174,12 @@ extern double PTpwl();
extern double PTpwl_derivative();
extern double PTuramp();
extern double PTuminus();
extern double PTeq0(double arg);
extern double PTne0(double arg);
extern double PTgt0(double arg);
extern double PTlt0(double arg);
extern double PTge0(double arg);
extern double PTle0(double arg);
/* And in IFeval.c */

View File

@ -65,6 +65,9 @@ libinp_la_SOURCES = \
sperror.c \
inp.h
inpptree.c : inpptree-parser.c
inpptree-parser.c inpptree-parser.h : inpptree-parser.y
bison $<
AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/frontend

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
/* A Bison parser, made by GNU Bison 2.4.1. */
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
TOK_NUM = 258,
TOK_STR = 259,
TOK_LE = 260,
TOK_LT = 261,
TOK_GE = 262,
TOK_GT = 263,
TOK_EQ = 264,
TOK_NE = 265,
TOK_OR = 266,
TOK_AND = 267,
NEG = 268
};
#endif
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
/* Line 1740 of yacc.c */
#line 29 "inpptree-parser.y"
double num;
const char *str;
struct INPparseNode *pnode;
/* Line 1740 of yacc.c */
#line 73 "inpptree-parser.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif

View File

@ -0,0 +1,112 @@
%{
#include <stdio.h>
#include "inpptree-parser.h"
extern int PTlex (YYSTYPE *lvalp, char **line);
extern int PTparse (char **line, struct INPparseNode **retval);
static void PTerror (char **line, struct INPparseNode **retval, char const *);
#if defined (_MSC_VER)
# define __func__ __FUNCTION__ /* __func__ is C99, but MSC can't */
#endif
%}
%name-prefix="PT"
%output="inpptree-parser.c"
%defines
%pure-parser
%parse-param {char **line}
%lex-param {char **line}
%parse-param {struct INPparseNode **retval}
%union {
double num;
const char *str;
struct INPparseNode *pnode;
}
%token <num> TOK_NUM
%token <str> TOK_STR
%token TOK_LE TOK_LT TOK_GE TOK_GT TOK_EQ TOK_NE
%type <pnode> exp nonempty_arglist
// Operator Precedence
%left ','
%right '?' ':'
%left TOK_OR
%left TOK_AND
%left TOK_EQ TOK_NE
%left TOK_LE TOK_LT TOK_GE TOK_GT
%left '-' '+'
%left '*' '/'
%left '^' /* exponentiation */
%left NEG '!' /* negation--unary minus, and boolean not */
%%
expression:
exp { *retval = $1; }
;
exp:
TOK_NUM { $$ = mknnode($1); }
| TOK_STR { $$ = mksnode($1); }
| exp '+' exp { $$ = mkbnode("+", $1, $3); }
| exp '-' exp { $$ = mkbnode("-", $1, $3); }
| exp '*' exp { $$ = mkbnode("*", $1, $3); }
| exp '/' exp { $$ = mkbnode("/", $1, $3); }
| exp '^' exp { $$ = mkbnode("^", $1, $3); }
| '(' exp ')' { $$ = $2; }
| '-' exp %prec NEG { $$ = mkfnode("-",$2); }
| TOK_STR '(' nonempty_arglist ')' { $$ = mkfnode($1, $3); }
| exp '?' exp ':' exp { $$ = mkfnode("ternary_fcn",
mkbnode(",",
mkbnode(",", $1, $3),
$5)); }
| exp TOK_EQ exp { $$ = mkfnode("eq0", mkbnode("-",$1,$3)); }
| exp TOK_NE exp { $$ = mkfnode("ne0", mkbnode("-",$1,$3)); }
| exp TOK_GT exp { $$ = mkfnode("gt0", mkbnode("-",$1,$3)); }
| exp TOK_LT exp { $$ = mkfnode("lt0", mkbnode("-",$1,$3)); }
| exp TOK_GE exp { $$ = mkfnode("ge0", mkbnode("-",$1,$3)); }
| exp TOK_LE exp { $$ = mkfnode("le0", mkbnode("-",$1,$3)); }
| exp TOK_OR exp { $$ = mkfnode("ne0",
mkbnode("+",
mkfnode("ne0", $1),
mkfnode("ne0", $3))); }
| exp TOK_AND exp { $$ = mkfnode("eq0",
mkbnode("+",
mkfnode("eq0", $1),
mkfnode("eq0", $3))); }
| '!' exp { $$ = mkfnode("eq0", $2); }
;
nonempty_arglist:
exp
| nonempty_arglist ',' exp { $$ = mkbnode(",", $1, $3); }
%%
/* Called by yyparse on error. */
static void
PTerror (char **line, struct INPparseNode **retval, char const *s)
{
fprintf (stderr, "%s: %s\n", __func__, s);
}

View File

@ -16,15 +16,14 @@ static INPparseNode *mkb(int type, INPparseNode * left,
INPparseNode * right);
static INPparseNode *mkf(int type, INPparseNode * arg);
static int PTcheck(INPparseNode * p);
static INPparseNode *PTparse(char **line);
static INPparseNode *makepnode(PTelement * elem);
static INPparseNode *mkbnode(int opnum, INPparseNode * arg1,
static INPparseNode *mkbnode(const char *opstr, INPparseNode * arg1,
INPparseNode * arg2);
static INPparseNode *mkfnode(char *fname, INPparseNode * arg);
static INPparseNode *mkfnode(const char *fname, INPparseNode * arg);
static INPparseNode *mknnode(double number);
static INPparseNode *mksnode(char *string);
static INPparseNode *mksnode(const char *string);
static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum);
static PTelement *PTlexer(char **line);
#include "inpptree-parser.c"
static IFvalue *values = NULL;
static int *types;
@ -85,7 +84,13 @@ static struct func {
/* MW. cif function added */
{ "u2", PTF_USTEP2, PTustep2},
{ "pwl", PTF_PWL, PTpwl},
{ "pwl_derivative", PTF_PWL_DERIVATIVE, PTpwl_derivative}
{ "pwl_derivative", PTF_PWL_DERIVATIVE, PTpwl_derivative},
{ "eq0", PTF_EQ0, PTeq0},
{ "ne0", PTF_NE0, PTne0},
{ "gt0", PTF_GT0, PTgt0},
{ "lt0", PTF_LT0, PTlt0},
{ "ge0", PTF_GE0, PTge0},
{ "le0", PTF_LE0, PTle0},
} ;
#define NUM_FUNCS (sizeof (funcs) / sizeof (struct func))
@ -112,7 +117,7 @@ void
INPgetTree(char **line, INPparseTree ** pt, void *ckt, INPtables * tab)
{
INPparseNode *p;
int i;
int i, rv;
values = NULL;
types = NULL;
@ -121,9 +126,13 @@ INPgetTree(char **line, INPparseTree ** pt, void *ckt, INPtables * tab)
circuit = ckt;
tables = tab;
p = PTparse(line);
#ifdef TRACE
fprintf(stderr,"%s, line = \"%s\"\n", __func__, *line);
#endif
if (!p || !PTcheck(p)) {
rv = PTparse(line, &p);
if (rv || !PTcheck(p)) {
*pt = NULL;
return;
}
@ -390,6 +399,12 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum)
break;
case PTF_USTEP:
case PTF_EQ0:
case PTF_NE0:
case PTF_GT0:
case PTF_LT0:
case PTF_GE0:
case PTF_LE0:
arg1 = mkcon((double) 0.0);
break;
@ -615,182 +630,25 @@ static int PTcheck(INPparseNode * p)
}
}
/* The operator-precedence table for the parser. */
#define G 1 /* Greater than. */
#define L 2 /* Less than. */
#define E 3 /* Equal. */
#define R 4 /* Error. */
static char prectable[11][11] = {
/* $ + - * / ^ u- ( ) v , */
/* $ */ {R, L, L, L, L, L, L, L, R, L, R},
/* + */ {G, G, G, L, L, L, L, L, G, L, G},
/* - */ {G, G, G, L, L, L, L, L, G, L, G},
/* * */ {G, G, G, G, G, L, L, L, G, L, G},
/* / */ {G, G, G, G, G, L, L, L, G, L, G},
/* ^ */ {G, G, G, G, G, L, L, L, G, L, G},
/* u-*/ {G, G, G, G, G, G, G, L, G, L, G},
/* ( */ {R, L, L, L, L, L, L, L, E, L, L},
/* ) */ {G, G, G, G, G, G, G, R, G, R, G},
/* v */ {G, G, G, G, G, G, G, G, G, R, G},
/* , */ {G, L, L, L, L, L, L, L, G, L, G}
};
/* Return an expr. */
static INPparseNode *PTparse(char **line)
{
PTelement stack[PT_STACKSIZE];
int sp = 0, st, i;
PTelement *top, *next;
INPparseNode *pn, *lpn, *rpn;
stack[0].token = TOK_END;
next = PTlexer(line);
while ((sp > 1) || (next->token != TOK_END)) {
/* Find the top-most terminal. */
i = sp;
do {
top = &stack[i--];
} while (top->token == TOK_VALUE);
switch (prectable[top->token][next->token]) {
case L:
case E:
/* Push the token read. */
if (sp == (PT_STACKSIZE - 1)) {
fprintf(stderr, "Error: stack overflow\n");
return (NULL);
}
bcopy((char *) next, (char *) &stack[++sp], sizeof(PTelement));
next = PTlexer(line);
continue;
case R:
fprintf(stderr, "Syntax error.\n");
return (NULL);
case G:
/* Reduce. Make st and sp point to the elts on the
* stack at the end and beginning of the junk to
* reduce, then try and do some stuff. When scanning
* back for a <, ignore VALUES.
*/
st = sp;
if (stack[sp].token == TOK_VALUE)
sp--;
while (sp > 0) {
if (stack[sp - 1].token == TOK_VALUE)
i = 2; /* No 2 pnodes together... */
else
i = 1;
if (prectable[stack[sp - i].token]
[stack[sp].token] == L)
break;
else
sp = sp - i;
}
if (stack[sp - 1].token == TOK_VALUE)
sp--;
/* Now try and see what we can make of this.
* The possibilities are: - node
* node op node
* ( node )
* func ( node )
* func ( node, node, node, ... ) <- new
* node
*/
if (st == sp) {
pn = makepnode(&stack[st]);
if (pn == NULL)
goto err;
} else if ((stack[sp].token == TOK_UMINUS) && (st == sp + 1)) {
lpn = makepnode(&stack[st]);
if (lpn == NULL)
goto err;
pn = mkfnode("-", lpn);
} else if ((stack[sp].token == TOK_LPAREN) &&
(stack[st].token == TOK_RPAREN)) {
pn = makepnode(&stack[sp + 1]);
if (pn == NULL)
goto err;
} else if ((stack[sp + 1].token == TOK_LPAREN) &&
(stack[st].token == TOK_RPAREN)) {
lpn = makepnode(&stack[sp + 2]);
if ((lpn == NULL) || (stack[sp].type != TYP_STRING))
goto err;
if (!(pn = mkfnode(stack[sp].value.string, lpn)))
return (NULL);
} else { /* node op node */
lpn = makepnode(&stack[sp]);
rpn = makepnode(&stack[st]);
if ((lpn == NULL) || (rpn == NULL))
goto err;
pn = mkbnode(stack[sp + 1].token, lpn, rpn);
}
stack[sp].token = TOK_VALUE;
stack[sp].type = TYP_PNODE;
stack[sp].value.pnode = pn;
continue;
}
}
pn = makepnode(&stack[1]);
if (pn)
return (pn);
err:
fprintf(stderr, "Syntax error.\n");
return (NULL);
}
/* Given a pointer to an element, make a pnode out of it (if it already
* is one, return a pointer to it). If it isn't of type VALUE, then return
* NULL.
*/
static INPparseNode *makepnode(PTelement * elem)
{
if (elem->token != TOK_VALUE)
return (NULL);
switch (elem->type) {
case TYP_STRING:
return (mksnode(elem->value.string));
case TYP_NUM:
return (mknnode(elem->value.real));
case TYP_PNODE:
return (elem->value.pnode);
default:
fprintf(stderr, "Internal Error: bad token type\n");
return (NULL);
}
}
/* Binop node. */
static INPparseNode *mkbnode(int opnum, INPparseNode * arg1,
static INPparseNode *mkbnode(const char *opstr, INPparseNode * arg1,
INPparseNode * arg2)
{
INPparseNode *p;
int i;
for (i = 0; i < NUM_OPS; i++)
if (ops[i].number == opnum)
if (!strcmp(ops[i].name, opstr))
break;
if (i == NUM_OPS) {
fprintf(stderr, "Internal Error: no such op num %d\n", opnum);
fprintf(stderr, "Internal Error: no such op num %s\n", opstr);
return (NULL);
}
p = (INPparseNode *) MALLOC(sizeof(INPparseNode));
p->type = opnum;
p->type = ops[i].number;
p->funcname = ops[i].name;
p->function = ops[i].funcptr;
p->left = arg1;
@ -885,7 +743,7 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
}
static INPparseNode *mkfnode(char *fname, INPparseNode * arg)
static INPparseNode *mkfnode(const char *fname, INPparseNode * arg)
{
int i;
INPparseNode *p;
@ -1033,7 +891,7 @@ static INPparseNode *mknnode(double number)
/* String node. */
static INPparseNode *mksnode(char *string)
static INPparseNode *mksnode(const char *string)
{
int i, j;
char buf[128], *s;
@ -1083,7 +941,7 @@ static INPparseNode *mksnode(char *string)
if (i == NUM_CONSTANTS) {
/* We'd better save this in case it's part of i(something). */
p->type = PT_PLACEHOLDER;
p->funcname = string;
p->funcname = (/*nonconst*/ char *) string;
} else {
p->type = PT_CONSTANT;
p->constant = constants[i].value;
@ -1094,110 +952,142 @@ static INPparseNode *mksnode(char *string)
/* The lexical analysis routine. */
static PTelement *PTlexer(char **line)
int PTlex (YYSTYPE *lvalp, char **line)
{
double td;
int err;
static PTelement el;
static char *specials = " \t()^+-*/,";
static int lasttoken = TOK_END, lasttype;
char *sbuf, *s;
int token;
sbuf = *line;
#ifdef TRACE
printf("entering lexer, sbuf = '%s', lastoken = %d, lasttype = %d\n",
sbuf, lasttoken, lasttype);
// printf("entering lexer, sbuf = '%s', lastoken = %d, lasttype = %d\n",
// sbuf, lasttoken, lasttype);
#endif
while ((*sbuf == ' ') || (*sbuf == '\t') || (*sbuf == '='))
while ((*sbuf == ' ') || (*sbuf == '\t'))
sbuf++;
switch (*sbuf) {
case '\0':
el.token = TOK_END;
token = 0;
break;
case '?':
case ':':
case ',':
el.token = TOK_COMMA;
sbuf++;
break;
case '-':
if ((lasttoken == TOK_VALUE) || (lasttoken == TOK_RPAREN))
el.token = TOK_MINUS;
else
el.token = TOK_UMINUS;
sbuf++;
break;
case '+':
el.token = TOK_PLUS;
sbuf++;
case '/':
case '^':
case '(':
case ')':
token = *sbuf++;
break;
case '*':
el.token = TOK_TIMES;
sbuf++;
break;
if(sbuf[1] == '*') {
sbuf += 2;
token = '^'; /* `**' is exponentiation */
break;
} else {
token = *sbuf++;
break;
}
case '/':
el.token = TOK_DIVIDE;
sbuf++;
break;
case '&':
if(sbuf[1] == '&') {
sbuf += 2;
token = TOK_AND;
break;
} else {
token = *sbuf++;
break;
}
case '^':
el.token = TOK_POWER;
sbuf++;
break;
case '|':
if(sbuf[1] == '|') {
sbuf += 2;
token = TOK_OR;
break;
} else {
token = *sbuf++;
break;
}
case '(':
if (((lasttoken == TOK_VALUE) && ((lasttype == TYP_NUM))) ||
(lasttoken == TOK_RPAREN)) {
el.token = TOK_END;
} else {
el.token = TOK_LPAREN;
sbuf++;
}
break;
case '=':
if(sbuf[1] == '=') {
sbuf += 2;
token = TOK_EQ;
break;
} else {
token = *sbuf++;
break;
}
case ')':
el.token = TOK_RPAREN;
sbuf++;
break;
case '!':
if(sbuf[1] == '=') {
sbuf += 2;
token = TOK_NE;
break;
} else {
token = *sbuf++;
break;
}
case '>':
if(sbuf[1] == '=') {
sbuf += 2;
token = TOK_GE;
break;
} else {
sbuf += 1;
token = TOK_GT;
break;
}
case '<':
if(sbuf[1] == '>') {
sbuf += 2;
token = TOK_NE;
break;
}
else if(sbuf[1] == '=') {
sbuf += 2;
token = TOK_LE;
break;
} else {
sbuf += 1;
token = TOK_LT;
break;
}
default:
if ((lasttoken == TOK_VALUE) || (lasttoken == TOK_RPAREN)) {
el.token = TOK_END;
break;
}
td = INPevaluate(&sbuf, &err, 1);
if (err == OK) {
el.token = TOK_VALUE;
el.type = TYP_NUM;
el.value.real = td;
token = TOK_NUM;
lvalp->num = td;
} else {
el.token = TOK_VALUE;
el.type = TYP_STRING;
char *tmp;
token = TOK_STR;
for (s = sbuf; *s; s++)
if (index(specials, *s))
break;
el.value.string = MALLOC(s - sbuf + 1);
strncpy(el.value.string, sbuf, s - sbuf);
el.value.string[s - sbuf] = '\0';
tmp = MALLOC(s - sbuf + 1);
strncpy(tmp, sbuf, s - sbuf);
tmp[s - sbuf] = '\0';
lvalp->str = tmp;
sbuf = s;
}
}
lasttoken = el.token;
lasttype = el.type;
*line = sbuf;
#ifdef TRACE
printf("PTlexer: token = %d, type = %d, left = '%s'\n",
el.token, el.type, sbuf);
// printf("PTlexer: token = %d, type = %d, left = '%s'\n",
// el.token, el.type, sbuf); */
#endif
return (&el);
return (token);
}
#ifdef TRACE

View File

@ -162,6 +162,41 @@ PTustep2(double arg)
return 1.0;
}
double
PTeq0(double arg)
{
return (arg == 0.0) ? 1.0 : 0.0;
}
double
PTne0(double arg)
{
return (arg != 0.0) ? 1.0 : 0.0;
}
double
PTgt0(double arg)
{
return (arg > 0.0) ? 1.0 : 0.0;
}
double
PTlt0(double arg)
{
return (arg < 0.0) ? 1.0 : 0.0;
}
double
PTge0(double arg)
{
return (arg >= 0.0) ? 1.0 : 0.0;
}
double
PTle0(double arg)
{
return (arg <= 0.0) ? 1.0 : 0.0;
}
double
PTuramp(double arg)