1 /**********
2 Copyright 1990 Regents of the University of California.  All rights reserved.
3 Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
4 **********/
5 
6 /*
7  * A simple operator-precedence parser for algebraic expressions.
8  * This also handles relational and logical expressions.
9  */
10 
11 #include "ngspice/ngspice.h"
12 #include "ngspice/bool.h"
13 #include "ngspice/fteparse.h"
14 #include "ngspice/fteext.h"
15 #include "ngspice/sim.h"
16 
17 #include "evaluate.h"
18 #include "parse.h"
19 #include "parse-bison.h"
20 #include "parse-bison-y.h"
21 
22 
23 static bool checkvalid(struct pnode *pn);
24 
25 #ifdef OLD_BISON
26 extern int PPparse(char **, struct pnode **);
27 #endif
28 
29 void db_print_pnode_tree(struct pnode *p, char *print);
30 
31 
ft_getpnames_from_string(const char * sz,bool check)32 struct pnode *ft_getpnames_from_string(const char *sz, bool check)
33 {
34     struct pnode *pn;
35 
36     /* The first argument to PPparse is not const char **, but it does not
37      * appear to modify the string that is being parsed */
38     if (PPparse((char **) &sz, &pn) != 0) {
39         return (struct pnode *) NULL;
40     }
41 
42     /* If validation is requested, do it and return NULL on failure. The
43      * structure must also be freed if the check fails since it is not
44      * being returned. */
45     if (check && !checkvalid(pn)) {
46         free_pnode(pn);
47         return (struct pnode *) NULL;
48     }
49 
50     return pn;
51 } /* end of function ft_getpnames_from_string */
52 
53 
54 
55 struct pnode *
ft_getpnames(const wordlist * wl,bool check)56 ft_getpnames(const wordlist *wl, bool check)
57 {
58     /* Validate input */
59     if (!wl) {
60         (void) fprintf(cp_err, "Warning: NULL arithmetic expression\n");
61         return (struct pnode *) NULL;
62     }
63 
64     /* Convert the list to a string, then parse the string */
65     const char * const sz = wl_flatten(wl);
66     struct pnode * const pn = ft_getpnames_from_string(sz, check);
67     txfree((void *) sz);
68 
69     return pn; /* Return the parsed result */
70 } /* end of function ft_getpnames */
71 
72 
73 
74 /* See if there are any variables around which have length 0 and are
75  * not named 'list'. There should really be another flag for this...
76  */
77 
78 static bool
checkvalid(struct pnode * pn)79 checkvalid(struct pnode *pn)
80 {
81     while (pn) {
82         if (pn->pn_value) {
83             if ((pn->pn_value->v_length == 0) &&
84                 !eq(pn->pn_value->v_name, "list")) {
85                 if (eq(pn->pn_value->v_name, "all"))
86                     fprintf(cp_err,
87                             "Error: %s: no matching vectors.\n",
88                             pn->pn_value->v_name);
89                 else
90                     fprintf(cp_err,
91                             "Error(parse.c--checkvalid): %s: zero length vector.\n",
92                             pn->pn_value->v_name);
93                 return (FALSE);
94             }
95         } else if (pn->pn_func || (pn->pn_op && (pn->pn_op->op_arity == 1))) {
96             if (!checkvalid(pn->pn_left))
97                 return (FALSE);
98         } else if (pn->pn_op && (pn->pn_op->op_arity == 2)) {
99             if (!checkvalid(pn->pn_left))
100                 return (FALSE);
101             if (!checkvalid(pn->pn_right))
102                 return (FALSE);
103         } else {
104             fprintf(cp_err,
105                     "checkvalid: Internal Error: bad node\n");
106         }
107         pn = pn->pn_next;
108     }
109     return (TRUE);
110 }
111 
112 
113 /* Some auxiliary functions for building the parse tree. */
114 
115 static struct op ops[] = {
116     { PT_OP_PLUS,     "+",   2, {(void(*)(void)) op_plus} },
117     { PT_OP_MINUS,    "-",   2, {(void(*)(void)) op_minus} },
118     { PT_OP_TIMES,    "*",   2, {(void(*)(void)) op_times} },
119     { PT_OP_MOD,      "%",   2, {(void(*)(void)) op_mod} },
120     { PT_OP_DIVIDE,   "/",   2, {(void(*)(void)) op_divide} },
121     { PT_OP_COMMA,    ",",   2, {(void(*)(void)) op_comma} },
122     { PT_OP_POWER,    "^",   2, {(void(*)(void)) op_power} },
123     { PT_OP_EQ,       "=",   2, {(void(*)(void)) op_eq} },
124     { PT_OP_GT,       ">",   2, {(void(*)(void)) op_gt} },
125     { PT_OP_LT,       "<",   2, {(void(*)(void)) op_lt} },
126     { PT_OP_GE,       ">=",  2, {(void(*)(void)) op_ge} },
127     { PT_OP_LE,       "<=",  2, {(void(*)(void)) op_le} },
128     { PT_OP_NE,       "<>",  2, {(void(*)(void)) op_ne} },
129     { PT_OP_AND,       "&",  2, {(void(*)(void)) op_and} },
130     { PT_OP_OR,       "|",   2, {(void(*)(void)) op_or} },
131     { PT_OP_INDX,     "[",   2, {(void(*)(void)) op_ind} },
132     { PT_OP_RANGE,    "[[",  2, {(void(*)(void)) op_range} },
133     { PT_OP_TERNARY,  "?:",  2, {NULL} },
134     { 0,               NULL, 0, {NULL} }
135 };
136 
137 
138 static struct op uops[] = {
139     { PT_OP_UMINUS, "-",  1, {(void(*)(void)) op_uminus} },
140     { PT_OP_NOT,    "~",  1, {(void(*)(void)) op_not} },
141     { 0,            NULL, 0, {NULL} }
142 };
143 
144 
145 /* We have 'v' declared as a function, because if we don't then the defines
146  * we do for vm(), etc won't work. This is caught in evaluate(). Bad kludge.
147  */
148 
149 typedef void* cx_function_t(void*, short int, int, int*, short int*);
150 
151 struct func ft_funcs[] = {
152     { "mag",         cx_mag },
153     { "magnitude",   cx_mag },
154     { "cph",         cx_cph },  /* SJdV */
155     { "cphase",      cx_cph },  /* SJdV Continious phase*/
156     { "unwrap",      cx_unwrap },
157     { "ph",          cx_ph },
158     { "phase",       cx_ph },
159     { "j",           cx_j },
160     { "real",        cx_real },
161     { "re",          cx_real },
162     { "imag",        cx_imag },
163     { "im",          cx_imag },
164     { "conj",        cx_conj },
165     { "db",          cx_db },
166     { "log",         cx_log },
167     { "log10",       cx_log10 },
168     { "ln",          cx_log },
169     { "exp",         cx_exp },
170     { "abs",         cx_mag },
171     { "sqrt",        cx_sqrt },
172     { "sin",         cx_sin },
173     { "cos",         cx_cos },
174     { "tan",         cx_tan },
175     { "sinh",        cx_sinh },
176     { "cosh",        cx_cosh },
177     { "tanh",        cx_tanh },
178     { "atan",        cx_atan },
179     { "sortorder",   cx_sortorder },
180     { "norm",        cx_norm },
181     { "rnd",         cx_rnd },
182     { "sunif",       cx_sunif },
183     { "poisson",     cx_poisson },
184     { "exponential", cx_exponential },
185     { "sgauss",      cx_sgauss },
186     { "pos",         cx_pos },
187     { "nint",        cx_nint },
188     { "floor",       cx_floor },
189     { "ceil",        cx_ceil },
190     { "mean",        cx_mean },
191     { "stddev",      cx_stddev },
192     { "avg",         cx_avg }, /* A.Roldan 03/06/05 incremental average new function */
193     { "group_delay", (cx_function_t*) cx_group_delay }, /* A.Roldan 10/06/05 group delay new function */
194     { "vector",      cx_vector },
195     { "unitvec",     cx_unitvec },
196     { "length",      cx_length },
197     { "vecmin",      cx_min },
198     { "minimum",     cx_min },
199     { "vecmax",      cx_max },
200     { "maximum",     cx_max },
201     { "vecd",        cx_d },
202     { "interpolate", (cx_function_t*) cx_interpolate },
203     { "deriv",       (cx_function_t*) cx_deriv },
204     { "fft",         (cx_function_t*) cx_fft },
205     { "ifft",        (cx_function_t*) cx_ifft },
206     { "v",           NULL },
207     { NULL,          NULL }
208 };
209 
210 struct func func_uminus = { "minus", cx_uminus };
211 
212 struct func func_not = { "not", cx_not };
213 
214 
215 /* Binary operator node. */
PP_mkbnode(int opnum,struct pnode * arg1,struct pnode * arg2)216 struct pnode *PP_mkbnode(int opnum, struct pnode *arg1, struct pnode *arg2)
217 {
218     struct op *o;
219     struct pnode *p;
220 
221     for (o = &ops[0]; o->op_name; o++) {
222         if (o->op_num == opnum) {
223             break;
224         }
225     }
226 
227     if (!o->op_name) {
228         fprintf(cp_err, "PP_mkbnode: Internal Error: no such op num %d\n",
229                 opnum);
230     }
231 
232     p = alloc_pnode();
233 
234     p->pn_op = o;
235 
236     p->pn_left = arg1;
237     if (p->pn_left) {
238         p->pn_left->pn_use++;
239     }
240 
241     p->pn_right = arg2;
242     if (p->pn_right) {
243         p->pn_right->pn_use++;
244     }
245 
246     return p;
247 } /* end of function PP_mkbnode */
248 
249 
250 
251 /* Unary operator node. */
PP_mkunode(int op,struct pnode * arg)252 struct pnode *PP_mkunode(int op, struct pnode *arg)
253 {
254     struct pnode *p;
255     struct op *o;
256 
257     p = alloc_pnode();
258 
259     for (o = uops; o->op_name; o++) {
260         if (o->op_num == op) {
261             break;
262         }
263     }
264 
265     if (!o->op_name) {
266         fprintf(cp_err, "PP_mkunode: Internal Error: no such op num %d\n",
267                 op);
268     }
269 
270     p->pn_op = o;
271 
272     p->pn_left = arg;
273     if (p->pn_left) {
274         p->pn_left->pn_use++;
275     }
276 
277     return p;
278 } /* end of function PP_mkunode */
279 
280 
281 
282 /* Function node. We have to worry about a lot of things here. Something
283  * like f(a) could be three things -- a call to a standard function, which
284  * is easiest to deal with, a variable name, in which case we do the
285  * kludge with 0-length lists, or it could be a user-defined function,
286  * in which case we have to figure out which one it is, substitute for
287  * the arguments, and then return a copy of the expression that it was
288  * defined to be.
289  */
PP_mkfnode(const char * func,struct pnode * arg)290 struct pnode *PP_mkfnode(const char *func, struct pnode *arg)
291 {
292     struct func *f;
293     struct pnode *p, *q;
294     struct dvec *d;
295     char buf[BSIZE_SP];
296 
297     (void) strcpy(buf, func);
298     strtolower(buf);  /* Make sure the case is ok. */
299 
300     for (f = &ft_funcs[0]; f->fu_name; f++) {
301         if (eq(f->fu_name, buf)) {
302             break;
303         }
304     }
305 
306     if (f->fu_name == NULL) { /* not found yet */
307         /* Give the user-defined functions a try. */
308         q = ft_substdef(func, arg);
309         if (q) { /* found */
310             /* remove only the old comma operator pnode, no longer used */
311             if (arg->pn_op && arg->pn_op->op_num == PT_OP_COMMA) {
312                 free_pnode(arg);
313             }
314             return q;
315         }
316     }
317 
318     if ((f->fu_name == NULL) && arg->pn_value) {
319         /* Kludge -- maybe it is really a variable name. */
320         (void) sprintf(buf, "%s(%s)", func, arg->pn_value->v_name);
321         free_pnode(arg);
322         d = vec_get(buf);
323         if (d == NULL) {
324             /* Well, too bad. */
325             fprintf(cp_err, "Error: no such function as %s.\n",
326                     func);
327             return (struct pnode *) NULL;
328         }
329         /* (void) strcpy(buf, d->v_name); XXX */
330         return PP_mksnode(buf);
331     }
332     else if (f->fu_name == NULL) {
333         fprintf(cp_err, "Error: no function as %s with that arity.\n",
334                 func);
335         free_pnode(arg);
336         return (struct pnode *) NULL;
337     }
338 
339     if (!f->fu_func && arg->pn_op && arg->pn_op->op_num == PT_OP_COMMA) {
340         p = PP_mkbnode(PT_OP_MINUS, PP_mkfnode(func, arg->pn_left),
341                     PP_mkfnode(func, arg->pn_right));
342         free_pnode(arg);
343         return p;
344     }
345 
346     p = alloc_pnode();
347 
348     p->pn_func = f;
349 
350     p->pn_left = arg;
351     if (p->pn_left) {
352         p->pn_left->pn_use++;
353     }
354 
355     return p;
356 } /* end of function PP_mkfnode */
357 
358 
359 
360 /* Number node. */
PP_mknnode(double number)361 struct pnode *PP_mknnode(double number)
362 {
363     struct pnode *p;
364     struct dvec *v;
365 
366     /* We don't use printnum because it screws up PP_mkfnode above. We have
367      * to be careful to deal properly with node numbers that are quite
368      * large...
369      */
370     v = dvec_alloc(number <= INT_MAX
371                    ? tprintf("%d", (int) number)
372                    : tprintf("%G", number),
373                    SV_NOTYPE,
374                    VF_REAL,
375                    1, NULL);
376 
377     v->v_realdata[0] = number;
378 
379     vec_new(v);
380 
381     p = alloc_pnode();
382     p->pn_value = v;
383     return (p);
384 } /* end of function PP_mknnode */
385 
386 
387 
388 /* String node. */
PP_mksnode(const char * string)389 struct pnode *PP_mksnode(const char *string)
390 {
391     struct dvec *v, *nv, *vs, *newv = NULL, *end = NULL;
392     struct pnode *p;
393 
394     p = alloc_pnode();
395     v = vec_get(string);
396     if (v == NULL) {
397         nv = dvec_alloc(copy(string),
398                         SV_NOTYPE,
399                         0,
400                         0, NULL);
401         p->pn_value = nv;
402         return p;
403     }
404 
405     /* It's not obvious that we should be doing this, but... */
406     for (vs = v; vs; vs = vs->v_link2) {
407         nv = vec_copy(vs);
408         vec_new(nv);
409         if (end) {
410             end->v_link2 = nv;
411         }
412         else {
413             newv = end = nv;
414         }
415         end = nv;
416     }
417     p->pn_value = newv;
418 
419     /* va: tfree v in case of @xxx[par], because vec_get created a new vec and
420        nobody will free it elsewhere */
421     /*if (v && v->v_name && *v->v_name == '@' && isreal(v) && v->v_realdata) {
422       vec_free(v);
423       } */
424     /* The two lines above have been commented out to prevent deletion of @xxx[par]
425        after execution of only a single command like plot @xxx[par] or write. We need to
426        monitor if this will lead to excessive memory usage. h_vogt 090221 */
427     return p;
428 } /* end of function PP_mksnode */
429 
430 
431 
alloc_pnode(void)432 struct pnode *alloc_pnode(void)
433 {
434     struct pnode *pn = TMALLOC(struct pnode, 1);
435 
436     pn->pn_use = 0;
437     pn->pn_name = NULL;
438 
439     // fixme, thats actually a union ...
440     pn->pn_value = NULL;
441     pn->pn_func = NULL;
442     pn->pn_op = NULL;
443 
444     pn->pn_left = NULL;
445     pn->pn_right = NULL;
446     pn->pn_next = NULL;
447 
448     return pn;
449 } /* end of function alloc_pnode */
450 
451 
452 
453 /* Don't call this directly, always use the free_pnode() macro.
454    The linked pnodes do not necessarily form a perfect tree as some nodes get
455    reused.  Hence, in this recursive walk through the 'tree', we only free
456    nodes that have their pn_use value at zero. Nodes that have pn_use values
457    above zero have the link severed and their pn_use value decremented.
458    In addition, we don't walk past nodes with pn_use values avoid zero, just
459    in case we have a circular reference (This probably does not happen in
460    practice, but it does no harm playing safe.) */
free_pnode_x(struct pnode * t)461 void free_pnode_x(struct pnode *t)
462 {
463     if (!t) {
464         return;
465     }
466 
467     /* Don't walk past nodes used elsewhere. We decrement the pn_use value here,
468        but the link gets severed by the action of the free_pnode() macro */
469     if (t->pn_use > 1) {
470         t->pn_use--;
471     }
472     else {
473         /* pn_use is now 1, so its safe to free the pnode */
474         free_pnode(t->pn_left);
475         free_pnode(t->pn_right);
476         free_pnode(t->pn_next);
477         tfree(t->pn_name); /* va: it is a copy() of original string, can be free'd */
478         if (t->pn_use == 1 && t->pn_value && !(t->pn_value->v_flags & VF_PERMANENT)) {
479             vec_free(t->pn_value); /* patch by Stefan Jones */
480         }
481         txfree(t);
482     }
483 } /* end of function free_pnode_x */
484 
485 
486 
db_print_func(FILE * fdst,struct func * f)487 static void db_print_func(FILE *fdst, struct func *f)
488 {
489     if (!f) {
490         fprintf(fdst, "nil");
491         return;
492     }
493 
494     fprintf(fdst, "(func :fu_name %s :fu_func %p)", f->fu_name, f->fu_func);
495 } /* end of function db_print_func */
496 
497 
498 
db_print_op(FILE * fdst,struct op * op)499 static void db_print_op(FILE *fdst, struct op *op)
500 {
501     if (!op) {
502         fprintf(fdst, "nil");
503         return;
504     }
505 
506     fprintf(fdst, "(op :op_num %d :op_name %s :op_arity %d :op_func %p)",
507             op->op_num, op->op_name, op->op_arity, op->op_func.anonymous);
508 } /* end of function db_print_op */
509 
510 
511 
db_print_dvec(FILE * fdst,struct dvec * d)512 static void db_print_dvec(FILE *fdst, struct dvec *d)
513 {
514     if (!d) {
515         fprintf(fdst, "nil");
516         return;
517     }
518 
519     fprintf(fdst, "(dvec :v_name %s :v_type %d :v_flags %d :v_length %d ...)",
520             d->v_name, d->v_type, d->v_flags, d->v_length);
521 } /* end of function db_print_dvec */
522 
523 
524 
db_print_pnode(FILE * fdst,struct pnode * p)525 static void db_print_pnode(FILE *fdst, struct pnode *p)
526 {
527     if (!p) {
528         fprintf(fdst, "nil\n");
529         return;
530     }
531 
532     if (!p->pn_name && p->pn_value && !p->pn_func && !p->pn_op &&
533         !p->pn_left && !p->pn_right && !p->pn_next) {
534         fprintf(fdst, "(pnode-value :pn_use %d", p->pn_use);
535         fprintf(fdst, " :pn_value "); db_print_dvec(fdst, p->pn_value);
536         fprintf(fdst, ")\n");
537         return;
538     }
539 
540     if (!p->pn_name && !p->pn_value && p->pn_func && !p->pn_op &&
541         !p->pn_right && !p->pn_next) {
542         fprintf(fdst, "(pnode-func :pn_use %d", p->pn_use);
543         fprintf(fdst, "\n :pn_func "); db_print_func(fdst, p->pn_func);
544         fprintf(fdst, "\n :pn_left "); db_print_pnode(fdst, p->pn_left);
545         fprintf(fdst, ")\n");
546         return;
547     }
548 
549     if (!p->pn_name && !p->pn_value && !p->pn_func && p->pn_op &&
550         !p->pn_next) {
551         fprintf(fdst, "(pnode-op :pn_use %d", p->pn_use);
552         fprintf(fdst, "\n :pn_op "); db_print_op(fdst, p->pn_op);
553         fprintf(fdst, "\n :pn_left "); db_print_pnode(fdst, p->pn_left);
554         fprintf(fdst, "\n :pn_right "); db_print_pnode(fdst, p->pn_right);
555         fprintf(fdst, ")\n");
556         return;
557     }
558 
559     fprintf(fdst, "(pnode :pn_name \"%s\" pn_use %d", p->pn_name, p->pn_use);
560     fprintf(fdst, "\n :pn_value "); db_print_dvec(fdst, p->pn_value);
561     fprintf(fdst, "\n :pn_func "); db_print_func(fdst, p->pn_func);
562     fprintf(fdst, "\n :pn_op "); db_print_op(fdst, p->pn_op);
563     fprintf(fdst, "\n :pn_left "); db_print_pnode(fdst, p->pn_left);
564     fprintf(fdst, "\n :pn_right "); db_print_pnode(fdst, p->pn_right);
565     fprintf(fdst, "\n :pn_next "); db_print_pnode(fdst, p->pn_next);
566     fprintf(fdst, "\n)\n");
567 } /* end of function db_print_pnode */
568 
569 
570 
db_print_pnode_tree(struct pnode * p,char * print)571 void db_print_pnode_tree(struct pnode *p, char *print)
572 {
573 #if 1
574     NG_IGNORE(print);
575     db_print_pnode(stdout, p);
576 #else
577     char *buf;
578     size_t  buf_size;
579     FILE *db_stream = open_memstream(&buf, &buf_size);
580     db_print_pnode(db_stream, p);
581     fclose(db_stream);
582     if (print)
583         printf("%s:%d: %s {%s}\n%s\n", __FILE__, __LINE__, __func__, print, buf);
584     tfree(buf);
585 #endif
586 } /* end of function db_print_pnode_tree */
587 
588 
589 
PPlex(YYSTYPE * lvalp,struct PPltype * llocp,char ** line)590 int PPlex(YYSTYPE *lvalp, struct PPltype *llocp, char **line)
591 {
592     static char *specials = " \t%()-^+*,/|&<>~=";
593     char  *sbuf = *line;
594     int token;
595 
596     while ((*sbuf == ' ') || (*sbuf == '\t')) {
597         sbuf++;
598     }
599 
600     llocp->start = sbuf;
601 
602 #define lexer_return(token_, length)                            \
603     do { token = token_; sbuf += length; goto done; } while(0)
604 
605     if ((sbuf[0] == 'g') && (sbuf[1] == 't') &&
606         strchr(specials, sbuf[2])) {
607         lexer_return('>', 2);
608     }
609     else if ((sbuf[0] == 'l') && (sbuf[1] == 't') &&
610                strchr(specials, sbuf[2])) {
611         lexer_return('<', 2);
612     }
613     else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') &&
614                strchr(specials, sbuf[2])) {
615         lexer_return(TOK_GE, 2);
616     }
617     else if ((sbuf[0] == 'l') && (sbuf[1] == 'e') &&
618                strchr(specials, sbuf[2])) {
619         lexer_return(TOK_LE, 2);
620     }
621     else if ((sbuf[0] == 'n') && (sbuf[1] == 'e') &&
622                strchr(specials, sbuf[2])) {
623         lexer_return(TOK_NE, 2);
624     }
625     else if ((sbuf[0] == 'e') && (sbuf[1] == 'q') &&
626                strchr(specials, sbuf[2])) {
627         lexer_return('=', 2);
628     }
629     else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') &&
630                strchr(specials, sbuf[2])) {
631         lexer_return('|', 2);
632     }
633     else if ((sbuf[0] == 'a') && (sbuf[1] == 'n') &&
634                (sbuf[2] == 'd') && strchr(specials, sbuf[3])) {
635         lexer_return('&', 3);
636     }
637     else if ((sbuf[0] == 'n') && (sbuf[1] == 'o') &&
638                (sbuf[2] == 't') && strchr(specials, sbuf[3])) {
639         lexer_return('~', 3);
640     }
641 
642     switch (*sbuf) {
643 
644     case '[':
645     case ']':
646         lexer_return(*sbuf, 1);
647 
648     case '>':
649     case '<': {
650         /* Workaround, The Frontend makes "<>" into "< >" */
651         size_t j = 1;
652         while (isspace_c(sbuf[j]))
653             j++;
654         if (((sbuf[j] == '<') || (sbuf[j] == '>')) && (sbuf[0] != sbuf[j])) {
655             /* Allow both <> and >< for NE. */
656             lexer_return(TOK_NE, j + 1);
657         }
658         else if (sbuf[1] == '=') {
659             lexer_return((sbuf[0] == '>') ? TOK_GE : TOK_LE, 2);
660         }
661         else {
662             lexer_return(*sbuf, 1);
663         }
664     }
665 
666     case '?':
667     case ':':
668     case ',':
669     case '+':
670     case '-':
671     case '*':
672     case '%':
673     case '/':
674     case '^':
675     case '(':
676     case ')':
677     case '=':
678     case '&':
679     case '|':
680     case '~':
681         lexer_return(*sbuf, 1);
682 
683     case '\0':
684         lexer_return(*sbuf, 0);
685 
686     case '"': {
687         char *start = ++sbuf;
688         while (*sbuf && (*sbuf != '"'))
689             sbuf++;
690         lvalp->str = copy_substring(start, sbuf);
691         if (*sbuf) {
692             sbuf++;
693         }
694         lexer_return(TOK_STR, 0);
695     }
696 
697     default: {
698         char *s = sbuf;
699         double val;
700 
701         if (ft_numparse(&s, FALSE, &val) >= 0 &&
702                 (!s || *s != ':')) {
703             sbuf = s;
704             lvalp->num = val;
705             lexer_return(TOK_NUM, 0);
706         }
707         else {
708             int atsign = 0;
709             char *start = sbuf;
710             /* It is bad how we have to recognise '[' -- sometimes
711              * it is part of a word, when it defines a parameter
712              * name, and otherwise it isn't.
713              *
714              * what is valid here ?
715              *   foo  dc1.foo  dc1.@m1[vth]
716              *   vthing#branch
717              *   i(vthing)
718              */
719             for (; *sbuf && !strchr(specials, *sbuf); sbuf++)
720                 if (*sbuf == '@') {
721                     atsign = 1;
722                 }
723                 else if (!atsign && *sbuf == '[') {
724                     break;
725                 }
726                 else if (*sbuf == ']') {
727                     if (atsign) {
728                         sbuf++;
729                     }
730                     break;
731                 }
732             /* keep the identifier i(vss) as a single token, even as dc1.i(vss) */
733                 else if (prefix("i(v", sbuf)) {
734                     if (get_r_paren(&sbuf) == 1) {
735                         fprintf(stderr, "Error: missing ')' in token\n    %s\n", start);
736                         break;
737                     }
738                     sbuf--;
739                 }
740 
741             lvalp->str = copy_substring(start, sbuf);
742             lexer_return(TOK_STR, 0);
743         }
744     }
745     } /* end of switch over characters */
746 
747 done:
748     if (ft_parsedb) {
749         if (token == TOK_STR) {
750             fprintf(stderr, "lexer: TOK_STR, \"%s\"\n", lvalp->str);
751         }
752         else if (token == TOK_NUM) {
753             fprintf(stderr, "lexer: TOK_NUM, %G\n", lvalp->num);
754         }
755         else {
756             fprintf(stderr, "lexer: token %d\n", token);
757         }
758     }
759 
760     *line = sbuf;
761     llocp->stop = sbuf;
762     return token;
763 } /* end of function PPlex */
764 
765 
766 
767