ternary operation in control blocks

This commit is contained in:
dwarning 2010-04-11 08:49:05 +00:00
parent cc5ede68e7
commit 5fcf9c2afe
11 changed files with 2501 additions and 567 deletions

View File

@ -1,3 +1,8 @@
2010-04-11 Dietmar Warning
* Robert Larice patch to allow ternary operation in control blocks:
* src/include/fteparse.h, ngspice.h
* src/frontend/parse*.*, evaluate.c, Makefile.am, src/misc/string.c, stringutil.h
2010-03-25 Dietmar Warning
* Bill Swartz patch:
* numparam/*.c, *.h, *.txt, misc/hash.c, string.c: local and global hash lists for subckts

View File

@ -192,3 +192,7 @@ libfte_la_SOURCES = \
AM_CPPFLAGS = -I$(top_srcdir)/src/include @X_CFLAGS@
MAINTAINERCLEANFILES = Makefile.in
parse-bison.c parse-bison.h : parse-bison.y
bison $<
parse.c : parse-bison.c

View File

@ -22,6 +22,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
/* static declarations */
static RETSIGTYPE sig_matherr(void);
static struct dvec * apply_func(struct func *func, struct pnode *arg);
static struct dvec *ft_ternary(struct pnode *node);
static char * mkcname(char what, char *v1, char *v2);
@ -60,8 +61,10 @@ ft_evaluate(struct pnode *node)
d = (struct dvec *)
((*node->pn_op->op_func) (node->pn_left));
else if (node->pn_op->op_arity == 2) {
d = (struct dvec *) ((*node->pn_op->op_func)
(node->pn_left, node->pn_right));
if(node->pn_op->op_num == TERNARY)
d = ft_ternary(node);
else
d = (*node->pn_op->op_func) (node->pn_left, node->pn_right);
}
} else {
fprintf(cp_err, "ft_evaluate: Internal Error: bad node\n");
@ -86,6 +89,60 @@ ft_evaluate(struct pnode *node)
}
static struct dvec *
ft_ternary(struct pnode *node)
{
struct dvec *v, *d, *cond;
struct pnode *arg;
int c;
if(!node->pn_right->pn_op || node->pn_right->pn_op->op_func != op_comma)
{
fprintf(cp_err, "Error: ft_ternary(), daemons ...\n");
return NULL;
}
cond = ft_evaluate(node->pn_left);
if(cond->v_link2) {
fprintf(cp_err, "Error: ft_ternary(), whats that ?\n");
return NULL;
}
if(cond->v_numdims != 1) {
fprintf(cp_err, "Error: ft_ternary(), condition must be scalar, but numdims=%d\n",
cond->v_numdims);
return NULL;
}
if(cond->v_length != 1) {
fprintf(cp_err, "Error: ft_ternary(), condition must be scalar, but length=%d\n",
cond->v_length);
return NULL;
}
c = isreal(cond)
? (cond->v_realdata[0] != 0.0)
: ((realpart(cond->v_compdata) != 0.0) ||
(imagpart(cond->v_compdata) != 0.0) );
arg = c
? node->pn_right->pn_left
: node->pn_right->pn_right;
v = ft_evaluate(arg);
d = vec_copy(v);
vec_new(d);
if (!arg->pn_value && v)
vec_free(v);
if (!node->pn_left->pn_value && cond)
vec_free(cond);
return d;
}
/* Operate on two vectors, and return a third with the data, length, and flags
* fields filled in. Add it to the current plot and get rid of the two args.
*/

1874
src/frontend/parse-bison.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
/* A Bison parser, made by GNU Bison 2.3. */
/* 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 2, 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
/* 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_GE = 261,
TOK_NE = 262,
TOK_LRANGE = 263,
TOK_RRANGE = 264,
NEG = 265
};
#endif
/* Tokens. */
#define TOK_NUM 258
#define TOK_STR 259
#define TOK_LE 260
#define TOK_GE 261
#define TOK_NE 262
#define TOK_LRANGE 263
#define TOK_RRANGE 264
#define NEG 265
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
#line 51 "parse-bison.y"
{
double num;
const char *str;
struct pnode *pnode;
}
/* Line 1529 of yacc.c. */
#line 75 "parse-bison.h"
YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
typedef struct YYLTYPE
{
int first_line;
int first_column;
int last_line;
int last_column;
} YYLTYPE;
# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
# define YYLTYPE_IS_DECLARED 1
# define YYLTYPE_IS_TRIVIAL 1
#endif

169
src/frontend/parse-bison.y Normal file
View File

@ -0,0 +1,169 @@
%{
#include <stdio.h>
#include <stdlib.h>
struct PPltype {
const char *start, *stop;
};
# define YYLTYPE struct PPltype
# define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
if (N) { \
(Current).start = YYRHSLOC(Rhs, 1).start; \
(Current).stop = YYRHSLOC(Rhs, N).stop; \
} else { \
(Current).start = (Current).stop = YYRHSLOC(Rhs, 0).stop; \
} \
while (0)
#include "parse-bison.h"
extern int PPlex (YYSTYPE *lvalp, struct PPltype *llocp, char **line);
extern int PPparse (char **line, struct pnode **retval);
extern int PPdebug;
static void PPerror (YYLTYPE *locp, char **line, struct pnode **retval, char const *);
#if defined (_MSC_VER)
# define __func__ __FUNCTION__ /* __func__ is C99, but MSC can't */
#endif
#define U(x) (void)x
%}
%name-prefix="PP"
%output="parse-bison.c"
%defines
%locations
%debug
%pure-parser
%parse-param {char **line}
%lex-param {char **line}
%parse-param {struct pnode **retval}
%union {
double num;
const char *str;
struct pnode *pnode;
}
/*
* This gramar has two expected shift/reduce conflicts
* exp1 '-' exp2 can
* o yield an exp, interpreting '-' as a binary operator
* o yield a list of two expressions
* exp1 and
* unary '-' exp2
* the first interpretation is favoured. (bison defaults to 'shift')
* TOK_STR '(' exp1 ')' can
* o yield an exp, per function application
* o yield a list of two expressions
* TOK_STR and
* '(' exp1 ')' which will be reduced to exp1
* the first interpretation is favoured. (bison defaults to 'shift')
*
* to verify:
* execute bison --report=state
*
* the %expect 2
* manifests my expectation, and will issue a `warning' when not met
*/
%expect 2
%token <num> TOK_NUM
%token <str> TOK_STR
%token TOK_LE TOK_GE TOK_NE TOK_LRANGE TOK_RRANGE
%type <pnode> exp exp_list one_exp
/* Operator Precedence */
%right '?' ':'
%left '|'
%left '&'
%left '=' TOK_NE TOK_LE '<' TOK_GE '>'
%left '~'
%right ','
%left '-' '+'
%left '*' '/' '%'
%right '^' /* exponentiation */
%left NEG /* negation--unary minus */
%left '[' ']'
%left TOK_LRANGE TOK_RRANGE
%%
/*
*/
expression:
{ *retval = NULL; }
| exp_list { *retval = $1; }
;
exp_list:
one_exp
| one_exp exp_list { $1->pn_next = $2; $2->pn_use ++; $$ = $1; }
;
one_exp:
exp {
$1->pn_name = copy_substring(@1.start, @1.stop);
$$ = $1;
}
;
exp:
TOK_NUM { $$ = mknnode($1); }
| TOK_STR { $$ = mksnode($1); }
| exp ',' exp { $$ = mkbnode(COMMA, $1, $3); }
| exp '+' exp { $$ = mkbnode(PLUS, $1, $3); }
| exp '-' exp { $$ = mkbnode(MINUS, $1, $3); }
| exp '*' exp { $$ = mkbnode(TIMES, $1, $3); }
| exp '%' exp { $$ = mkbnode(MOD, $1, $3); }
| exp '/' exp { $$ = mkbnode(DIVIDE, $1, $3); }
| exp '^' exp { $$ = mkbnode(POWER, $1, $3); }
| '(' exp ')' { $$ = $2; }
| '-' exp %prec NEG { $$ = mkunode(UMINUS, $2); }
| '~' exp { $$ = mkunode(NOT, $2); }
| TOK_STR '(' exp ')' { $$ = mkfnode($1, $3); }
| exp '=' exp { $$ = mkbnode(EQ, $1, $3); }
| exp TOK_NE exp { $$ = mkbnode(NE, $1, $3); }
| exp '>' exp { $$ = mkbnode(GT, $1, $3); }
| exp '<' exp { $$ = mkbnode(LT, $1, $3); }
| exp TOK_GE exp { $$ = mkbnode(GE, $1, $3); }
| exp TOK_LE exp { $$ = mkbnode(LE, $1, $3); }
| exp '&' exp { $$ = mkbnode(AND, $1, $3); }
| exp '|' exp { $$ = mkbnode(OR, $1, $3); }
| exp '[' exp ']' { $$ = mkbnode(INDX, $1, $3); }
| exp TOK_LRANGE exp TOK_RRANGE { $$ = mkbnode(RANGE, $1, $3); }
| exp '?' exp ':' exp { $$ = mkbnode(TERNARY,$1,
mkbnode(COMMA,$3,$5)); }
;
%%
/* Called by yyparse on error. */
static void
PPerror (YYLTYPE *locp, char **line, struct pnode **retval, char const *s)
{
U(line); U(retval);
fprintf (stderr, "%s: %s\n", __func__, s);
}

View File

@ -20,66 +20,46 @@ $Id$
/* static declarations */
static bool checkvalid(struct pnode *pn);
static struct element * lexer(void);
static struct pnode * parse(void);
static struct pnode * makepnode(struct element *elem);
static struct pnode * mkbnode(int opnum, struct pnode *arg1, struct pnode *arg2);
static struct pnode * mkunode(int op, struct pnode *arg);
static struct pnode * mkfnode(char *func, struct pnode *arg);
static struct pnode * mkfnode(const char *func, struct pnode *arg);
static struct pnode * mknnode(double number);
static struct pnode * mksnode(char *string);
/*static void print_elem(struct element *elem); / va: for debugging /
static char * get_token_name(int e_token); / va, for debugging */
static struct pnode * mksnode(const char *string);
#include "parse-bison.c"
char * db_print_pnode_tree(struct pnode *p, char *print);
static int lasttoken = END, lasttype;
static char *sbuf;
struct pnode *
ft_getpnames(wordlist *wl, bool check)
{
struct pnode *pn = NULL, *lpn = NULL, *p;
char *xsbuf;
char buf[BSIZE_SP], *thisone, *s;
struct pnode *pn;
char *xsbuf, *sbuf;
int rv;
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;
while(--s>=buf && isspace(*s))
;
s[1] = '\0';
p->pn_name = copy(buf);
rv = PPparse (&sbuf, &pn);
if (pn) {
lpn->pn_next = p;
p->pn_use++;
lpn = p;
} else
pn = lpn = p;
}
tfree(xsbuf);
if (check)
if (!checkvalid(pn))
return (NULL);
if(rv)
return (NULL);
if (check && !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...
*/
@ -118,526 +98,6 @@ checkvalid(struct pnode *pn)
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...
*/
/* va: the structure returned is static, e_string is a copy
(in case of e_token==VALUE,e_type==STRING) */
static struct element *
lexer(void)
{
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') &&
strchr(specials, sbuf[2])) {
el.e_token = GT;
sbuf += 2;
} else if ((sbuf[0] == 'l') && (sbuf[1] == 't') &&
strchr(specials, sbuf[2])) {
el.e_token = LT;
sbuf += 2;
} else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') &&
strchr(specials, sbuf[2])) {
el.e_token = GE;
sbuf += 2;
} else if ((sbuf[0] == 'l') && (sbuf[1] == 'e') &&
strchr(specials, sbuf[2])) {
el.e_token = LE;
sbuf += 2;
} else if ((sbuf[0] == 'n') && (sbuf[1] == 'e') &&
strchr(specials, sbuf[2])) {
el.e_token = NE;
sbuf += 2;
} else if ((sbuf[0] == 'e') && (sbuf[1] == 'q') &&
strchr(specials, sbuf[2])) {
el.e_token = EQ;
sbuf += 2;
} else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') &&
strchr(specials, sbuf[2])) {
el.e_token = OR;
sbuf += 2;
} else if ((sbuf[0] == 'a') && (sbuf[1] == 'n') &&
(sbuf[2] == 'd') &&strchr(specials, sbuf[3])) {
el.e_token = AND;
sbuf += 3;
} else if ((sbuf[0] == 'n') && (sbuf[1] == 'o') &&
(sbuf[2] == 't') &&strchr(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.
* va, ']' too
*/
atsign = 0;
for (s = el.e_string; *s && !index(specials, *s); s++, sbuf++) {
if (*s == '@')
atsign = 1;
else if (!atsign && ( *s == '[' || *s == ']' ) )
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 200
static 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(void)
{
struct element stack[STACKSIZE];
int sp = 0, st, i, spmax=0; /* va: spmax = maximal used stack */
struct element *top, *next;
struct pnode *pn, *lpn, *rpn;
char rel;
char * parse_string=sbuf; /* va, duplicate sbuf's pointer for error message only, no tfree */
stack[0].e_token = END;
next = lexer();
while ((sp > 1) || (next->e_token != END)) {
/* Find the top-most terminal. */
/* va: no stack understepping, because stack[0].e_token==END */
i = sp;
do {
top = &stack[i--];
} while (top->e_token == VALUE && i>=0); /* va: do not understep stack */
if (top->e_token == VALUE) {
fprintf(cp_err, "Error: in parse.c(parse) stack understep.\n");
return (NULL);
}
/*for (i=0; i<=sp; i++) print_elem(stack+i); printf("next: "); print_elem(next); printf("\n");*/
rel = prectable[top->e_token][next->e_token];
switch (rel) {
case L:
case E:
/* Push the token read. */
if (sp == (STACKSIZE - 1)) {
fprintf(cp_err, "Error: stack overflow\n");
return (NULL);
}
bcopy((char *) next, (char *) &stack[++sp],
sizeof (struct element));
if (spmax<sp) spmax=sp; /* va: maximal used stack increased */
next = lexer();
continue;
case R:
fprintf(cp_err, "Syntax error: parsing expression '%s'.\n", parse_string);
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].e_token == VALUE)
sp--;
while (sp > 0) {
if (stack[sp - 1].e_token == VALUE)
i = 2; /* No 2 pnodes together... */
else
i = 1;
if (prectable[stack[sp - i].e_token]
[stack[sp].e_token] == L)
break;
else
sp = sp - i;
}
if (stack[sp - 1].e_token == VALUE)
sp--;
/* Now try and see what we can make of this.
* The possibilities are: unop node
* node op node
* ( node )
* func ( node )
* node
* node [ node ] is considered node op node.
*/
if (st == sp) {
pn = makepnode(&stack[st]);
if (pn == NULL)
goto err;
} else if (((stack[sp].e_token == UMINUS) ||
(stack[sp].e_token == NOT)) &&
(st == sp + 1)) {
lpn = makepnode(&stack[st]);
if (lpn == NULL)
goto err;
pn = mkunode(stack[sp].e_token, lpn);
} else if ((stack[sp].e_token == LPAREN) &&
(stack[st].e_token == RPAREN)) {
pn = makepnode(&stack[sp + 1]);
if (pn == NULL)
goto err;
} else if ((stack[sp + 1].e_token == LPAREN) &&
(stack[st].e_token == RPAREN)) {
lpn = makepnode(&stack[sp + 2]);
if ((lpn == NULL) || (stack[sp].e_type !=
STRING))
goto err;
if (!(pn = mkfnode(stack[sp].e_string, lpn)))
return (NULL);
/* va: avoid memory leakage:
in case of variablenames (i.e. i(vd)) mkfnode makes in
reality a snode, the old lpn (and its plotless vector) is
then a memory leak */
if (pn->pn_func==NULL && pn->pn_value!=NULL) /* a snode */
{
if (lpn->pn_value && lpn->pn_value->v_plot==NULL)
{
tfree(lpn->pn_value->v_name);
tfree(lpn->pn_value);
}
free_pnode(lpn);
}
} else { /* node op node */
lpn = makepnode(&stack[sp]);
rpn = makepnode(&stack[st]);
if ((lpn == NULL) || (rpn == NULL))
goto err;
pn = mkbnode(stack[sp + 1].e_token,
lpn, rpn);
}
/* va: avoid memory leakage: tfree all old strings on stack,
copied up to now within lexer */
for (i=sp; i<=spmax; i++) {
if (stack[i].e_token==VALUE && stack[i].e_type==STRING) {
tfree(stack[i].e_string);
}
}
spmax=sp; /* up to there stack is now clean */
stack[sp].e_token = VALUE;
stack[sp].e_type = PNODE;
stack[sp].e_pnode = pn;
continue;
}
}
pn = makepnode(&stack[1]);
/* va: avoid memory leakage: tfree all remaining strings,
copied within lexer */
for (i=0; i<=spmax; i++) {
if (stack[i].e_token == VALUE && stack[i].e_type == STRING) {
tfree(stack[i].e_string);
}
}
if (next->e_token == VALUE && next->e_type == STRING) {
tfree(next->e_string);
}
if (pn)
return (pn);
err:
fprintf(cp_err, "Syntax error: expression not understood '%s'.\n", parse_string);
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 struct pnode *
makepnode(struct element *elem)
{
if (elem->e_token != VALUE)
return (NULL);
switch (elem->e_type) {
case STRING:
return (mksnode(elem->e_string));
case NUM:
return (mknnode(elem->e_double));
case PNODE:
return (elem->e_pnode);
default:
return (NULL);
}
}
/*
static char * get_token_name(int e_token)
{
/ see include/fteparse.h /
switch (e_token) {
case 0: return "END ";
case 1: return "PLUS ";
case 2: return "MINUS ";
case 3: return "TIMES ";
case 4: return "MOD ";
case 5: return "DIVIDE";
case 6: return "POWER ";
case 7: return "UMINUS";
case 8: return "LPAREN";
case 9: return "RPAREN";
case 10: return "COMMA ";
case 11: return "VALUE ";
case 12: return "EQ ";
case 13: return "GT ";
case 14: return "LT ";
case 15: return "GE ";
case 16: return "LE ";
case 17: return "NE ";
case 18: return "AND ";
case 19: return "OR ";
case 20: return "NOT ";
case 21: return "INDX ";
case 22: return "RANGE ";
default : return "UNKNOWN";
}
}
static void print_elem(struct element *elem)
{
printf("e_token = %d(%s)", elem->e_token, get_token_name(elem->e_token));
if (elem->e_token == VALUE) {
printf(", e_type = %d", elem->e_type);
switch (elem->e_type) {
case STRING:
printf(", e_string = %s(%p)", elem->e_string,elem->e_string);
break;
case NUM:
printf(", e_double = %g", elem->e_double); break;
case PNODE:
printf(", e_pnode = %p", elem->e_pnode); break;
default:
break;
}
}
printf("\n");
}
*/
/* Some auxiliary functions for building the parse tree. */
@ -661,6 +121,7 @@ struct op ops[] = {
{ OR, "|", 2, op_or } ,
{ INDX, "[", 2, op_ind } ,
{ RANGE, "[[", 2, op_range } ,
{ TERNARY, "?:", 2, NULL } ,
{ 0, NULL, 0, NULL }
} ;
@ -700,8 +161,8 @@ struct func ft_funcs[] = {
{ "rnd", cx_rnd } ,
{ "pos", cx_pos } ,
{ "mean", cx_mean } ,
{ "avg", cx_avg } , //A.Rroldan 03/06/05 incremental average new function
{ "group_delay", cx_group_delay } , //A.Rroldan 10/06/05 group delay new function
{ "avg", cx_avg } , /* A.Roldan 03/06/05 incremental average new function */
{ "group_delay", cx_group_delay } , /* A.Roldan 10/06/05 group delay new function */
{ "vector", cx_vector } ,
{ "unitvec", cx_unitvec } ,
{ "length", cx_length } ,
@ -784,7 +245,7 @@ mkunode(int op, struct pnode *arg)
*/
static struct pnode *
mkfnode(char *func, struct pnode *arg)
mkfnode(const char *func, struct pnode *arg)
{
struct func *f;
struct pnode *p, *q;
@ -884,7 +345,7 @@ mknnode(double number)
/* String node. */
static struct pnode *
mksnode(char *string)
mksnode(const char *string)
{
struct dvec *v, *nv, *vs, *newv = NULL, *end = NULL;
struct pnode *p;
@ -973,3 +434,256 @@ free_pnode_o(struct pnode *t)
static void
db_print_func(FILE *fdst, struct func *f)
{
if(!f) {
fprintf(fdst,"nil");
return;
}
fprintf(fdst,"(func :fu_name %s :fu_func %p)", f->fu_name, f->fu_func);
}
static void
db_print_op(FILE *fdst, struct op *op)
{
if(!op) {
fprintf(fdst,"nil");
return;
}
fprintf(fdst,"(op :op_num %d :op_name %s :op_arity %d :op_func %p)",
op->op_num, op->op_name, op->op_arity, op->op_func);
}
static void
db_print_dvec(FILE *fdst, struct dvec *d)
{
if(!d) {
fprintf(fdst,"nil");
return;
}
fprintf(fdst,"(dvec :v_name %s :v_type %d :v_flags %d :v_length %d ...)",
d->v_name, d->v_type, d->v_flags, d->v_length);
}
static void
db_print_pnode(FILE *fdst, struct pnode *p)
{
if(!p) {
fprintf(fdst,"nil\n");
return;
}
if(!p->pn_name && p->pn_value && !p->pn_func && !p->pn_op
&& !p->pn_left && !p->pn_right && !p->pn_next) {
fprintf(fdst,"(pnode-value :pn_use %d", p->pn_use);
fprintf(fdst," :pn_value "); db_print_dvec(fdst, p->pn_value);
fprintf(fdst,")\n");
return;
}
if (!p->pn_name && !p->pn_value && p->pn_func && !p->pn_op
&& !p->pn_right && !p->pn_next) {
fprintf(fdst,"(pnode-func :pn_use %d", p->pn_use);
fprintf(fdst,"\n :pn_func "); db_print_func(fdst, p->pn_func);
fprintf(fdst,"\n :pn_left "); db_print_pnode(fdst, p->pn_left);
fprintf(fdst,")\n");
return;
}
if (!p->pn_name && !p->pn_value && !p->pn_func && p->pn_op
&& !p->pn_next) {
fprintf(fdst,"(pnode-op :pn_use %d", p->pn_use);
fprintf(fdst,"\n :pn_op "); db_print_op(fdst, p->pn_op);
fprintf(fdst,"\n :pn_left "); db_print_pnode(fdst, p->pn_left);
fprintf(fdst,"\n :pn_right "); db_print_pnode(fdst, p->pn_right);
fprintf(fdst,")\n");
return;
}
fprintf(fdst,"(pnode :pn_name \"%s\" pn_use %d", p->pn_name, p->pn_use);
fprintf(fdst,"\n :pn_value "); db_print_dvec(fdst, p->pn_value);
fprintf(fdst,"\n :pn_func "); db_print_func(fdst, p->pn_func);
fprintf(fdst,"\n :pn_op "); db_print_op(fdst, p->pn_op);
fprintf(fdst,"\n :pn_left "); db_print_pnode(fdst, p->pn_left);
fprintf(fdst,"\n :pn_right "); db_print_pnode(fdst, p->pn_right);
fprintf(fdst,"\n :pn_next "); db_print_pnode(fdst, p->pn_next);
fprintf(fdst,"\n)\n");
}
char *
db_print_pnode_tree(struct pnode *p, char *print)
{
#if 1
db_print_pnode(stdout, p);
return NULL;
#else
char *buf;
size_t buf_size;
FILE *db_stream = open_memstream (&buf, &buf_size);
db_print_pnode(db_stream, p);
fclose(db_stream);
if(print)
printf("%s:%d: %s {%s}\n%s\n", __FILE__, __LINE__, __func__, print, buf);
return buf;
#endif
}
int
PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
{
static char *specials = " \t%()-^+*,/|&<>~=";
char *sbuf = *line;
int token;
while ((*sbuf == ' ') || (*sbuf == '\t'))
sbuf++;
llocp->start = sbuf;
#define lexer_return(token_, length) \
do { token = token_; sbuf += length; goto done; } while(0)
if ((sbuf[0] == 'g') && (sbuf[1] == 't') &&
strchr(specials, sbuf[2])) {
lexer_return('>', 2);
} else if ((sbuf[0] == 'l') && (sbuf[1] == 't') &&
strchr(specials, sbuf[2])) {
lexer_return('<', 2);
} else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') &&
strchr(specials, sbuf[2])) {
lexer_return(TOK_GE, 2);
} else if ((sbuf[0] == 'l') && (sbuf[1] == 'e') &&
strchr(specials, sbuf[2])) {
lexer_return(TOK_LE, 2);
} else if ((sbuf[0] == 'n') && (sbuf[1] == 'e') &&
strchr(specials, sbuf[2])) {
lexer_return(TOK_NE, 2);
} else if ((sbuf[0] == 'e') && (sbuf[1] == 'q') &&
strchr(specials, sbuf[2])) {
lexer_return('=', 2);
} else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') &&
strchr(specials, sbuf[2])) {
lexer_return('|', 2);
} else if ((sbuf[0] == 'a') && (sbuf[1] == 'n') &&
(sbuf[2] == 'd') && strchr(specials, sbuf[3])) {
lexer_return('&', 3);
} else if ((sbuf[0] == 'n') && (sbuf[1] == 'o') &&
(sbuf[2] == 't') && strchr(specials, sbuf[3])) {
lexer_return('~', 3);
}
switch (*sbuf) {
case '[':
if (sbuf[1] == '[') {
lexer_return(TOK_LRANGE, 2);
} else {
lexer_return(*sbuf, 1);
}
case ']':
if (sbuf[1] == ']') {
lexer_return(TOK_RRANGE, 2);
} else {
lexer_return(*sbuf, 1);
}
case '>':
case '<':
{
/* Workaround, The Frontend makes "<>" into "< >" */
int j = 1;
while (isspace(sbuf[j]))
j++;
if (((sbuf[j] == '<') || (sbuf[j] == '>')) && (sbuf[0] != sbuf[j])) {
/* Allow both <> and >< for NE. */
lexer_return(TOK_NE, j+1);
} else if (sbuf[1] == '=') {
lexer_return((sbuf[0] == '>') ? TOK_GE : TOK_LE, 2);
} else {
lexer_return(*sbuf, 1);
}
}
case '?':
case ':':
case ',':
case '+':
case '-':
case '*':
case '%':
case '/':
case '^':
case '(':
case ')':
case '=':
case '&':
case '|':
case '~':
lexer_return(*sbuf, 1);
case '\0':
lexer_return(*sbuf, 0);
case '"':
{
char *start = ++sbuf;
while(*sbuf && (*sbuf != '"'))
sbuf++;
lvalp->str = copy_substring(start, sbuf);
if(*sbuf)
sbuf++;
lexer_return(TOK_STR, 0);
}
default:
{
char *s = sbuf;
double *td = ft_numparse(&s, FALSE);
if ((!s || *s != ':') && td) {
sbuf = s;
lvalp->num = *td;
lexer_return(TOK_NUM, 0);
} else {
int atsign = 0;
char *start = sbuf;
/* 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.
* va, ']' too
*/
for (; *sbuf && !index(specials, *sbuf); sbuf++)
if (*sbuf == '@')
atsign = 1;
else if (!atsign && ( *sbuf == '[' || *sbuf == ']' ))
break;
lvalp->str = copy_substring(start, sbuf); /* XXXX !!!! */
lexer_return(TOK_STR, 0);
}
}
}
done:
if (ft_parsedb) {
if(token == TOK_STR)
fprintf(stderr, "lexer: TOK_STR, \"%s\"\n", lvalp->str);
else if(token == TOK_NUM)
fprintf(stderr, "lexer: TOK_NUM, %G\n", lvalp->num);
else
fprintf(stderr, "lexer: token %d\n", token);
}
*line = sbuf;
llocp->stop = sbuf;
return (token);
}

View File

@ -97,6 +97,7 @@ struct element {
#define NOT 20
#define INDX 21
#define RANGE 22
#define TERNARY 23
#define NUM 1
#define STRING 2

View File

@ -214,7 +214,7 @@ extern char *absolute_pathname(char *str, char *dot_path);
extern char *smktemp(char *id);
extern char *copy(char *str);
extern char *copy(const char *str);
extern int prefix(char *p, char *str);
extern int substring(char *sub, char *str);
extern void cp_printword(char *str, FILE *fp);

View File

@ -24,7 +24,7 @@ prefix(register char *p, register char *s)
/* Create a copy of a string. */
char *
copy(char *str)
copy(const char *str)
{
char *p;
@ -33,6 +33,19 @@ copy(char *str)
return(p);
}
char *
copy_substring(const char *str, const char *end)
{
int n = end - str;
char *p;
if ((p = tmalloc(n + 1))) {
(void) strncpy(p, str, n);
p[n] = '\0';
}
return(p);
}
/* Determine whether sub is a substring of str. */
/* Like strstr( ) XXX */

View File

@ -10,7 +10,8 @@
#define STRING_H_INCLUDED
int prefix(register char *p, register char *s);
char * copy(char *str);
char * copy(const char *str);
char * copy_substring(const char *str, const char *end);
int substring(register char *sub, register char *str);
void appendc(char *s, char c);
int scannum(char *str);