new parser for B source
This commit is contained in:
parent
4068f498c6
commit
75d891e4c0
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue