ternary operation in control blocks
This commit is contained in:
parent
cc5ede68e7
commit
5fcf9c2afe
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ struct element {
|
|||
#define NOT 20
|
||||
#define INDX 21
|
||||
#define RANGE 22
|
||||
#define TERNARY 23
|
||||
|
||||
#define NUM 1
|
||||
#define STRING 2
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue