cexp.y 28.4 KB
Newer Older
1
%{
2
3
/* $Id$ */
/* Grammar definition and lexical analyzer for Cexp */
strauman's avatar
strauman committed
4

5
6
7
8
9
10
11
12
13
14
/* SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
 *
 * Authorship
 * ----------
 * This software (CEXP - C-expression interpreter and runtime
 * object loader/linker) was created by
 *
 *    Till Straumann <strauman@slac.stanford.edu>, 2002-2008,
 * 	  Stanford Linear Accelerator Center, Stanford University.
 *
strauman's avatar
strauman committed
15
 * Acknowledgement of sponsorship
16
17
18
19
 * ------------------------------
 * This software was produced by
 *     the Stanford Linear Accelerator Center, Stanford University,
 * 	   under Contract DE-AC03-76SFO0515 with the Department of Energy.
strauman's avatar
strauman committed
20
21
 * 
 * Government disclaimer of liability
22
 * ----------------------------------
strauman's avatar
strauman committed
23
 * Neither the United States nor the United States Department of Energy,
24
25
 * nor any of their employees, makes any warranty, express or implied, or
 * assumes any legal liability or responsibility for the accuracy,
strauman's avatar
strauman committed
26
 * completeness, or usefulness of any data, apparatus, product, or process
27
28
 * disclosed, or represents that its use would not infringe privately owned
 * rights.
strauman's avatar
strauman committed
29
30
 * 
 * Stanford disclaimer of liability
31
 * --------------------------------
strauman's avatar
strauman committed
32
33
34
 * Stanford University makes no representations or warranties, express or
 * implied, nor assumes any liability for the use of this software.
 * 
35
36
37
38
39
 * Stanford disclaimer of copyright
 * --------------------------------
 * Stanford University, owner of the copyright, hereby disclaims its
 * copyright and all other rights in this software.  Hence, anyone may
 * freely use it for any purpose without restriction.  
strauman's avatar
strauman committed
40
 * 
41
42
 * Maintenance of notices
 * ----------------------
strauman's avatar
strauman committed
43
 * In the interest of clarity regarding the origin and status of this
44
45
46
47
48
49
50
51
 * SLAC software, this and all the preceding Stanford University notices
 * are to remain affixed to any copy or derivative of this software made
 * or distributed by the recipient and are to be affixed to any copy of
 * software made or distributed by the recipient that contains a copy or
 * derivative of this software.
 * 
 * SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
 */ 
strauman's avatar
strauman committed
52

53
#include <stdio.h>
54
#include <sys/errno.h>
55
#include <fcntl.h>
56
#include <assert.h>
57
58
59
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
till's avatar
till committed
60
#include "cexpsyms.h"
till's avatar
till committed
61
#include "cexpmod.h"
62
#include "vars.h"
63
#include <stdarg.h>
64

65
66
67
68
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

69
70
71
72
73
/* not letting them live makes not much sense */
#ifndef CONFIG_STRINGS_LIVE_FOREVER
#define CONFIG_STRINGS_LIVE_FOREVER
#endif

74
#define YYLEX_PARAM		ctx
75
#define YYERROR_VERBOSE
76

77
#define EVAL_INH	 ((ctx)->evalInhibit)
78
#define PSHEVAL(inh) do { EVAL_INH<<=1; if (inh) EVAL_INH++; } while(0)
79
#define POPEVAL      do { EVAL_INH>>=1; } while(0)
80
81
#define EVAL(stuff)  if (! EVAL_INH ) do { stuff; } while (0)

82
#define CHECK(cexpTfuncall) do { const char *e=(cexpTfuncall);\
83
					 if (e) { yyerror(ctx, e); YYERROR; } } while (0)
84

85
86
87
/* acceptable characters for identifiers - must not
 * overlap with operators
 */
88
#define ISIDENTCHAR(ch) ('_'==(ch) || '@'==(ch))
89

90
#define LEXERR	-1
91
92
93
/* ugly hack; helper for word completion */
#define LEXERR_INCOMPLETE_STRING	-100

94
95
96
97
       void yyerror(CexpParserCtx ctx, const char*msg);
static void errmsg(CexpParserCtx ctx, const char *msg, ...);
static void wrnmsg(CexpParserCtx ctx, const char *msg, ...);

98
int  yylex();
99

100
101
typedef char *LString;

102
103
104
105
struct CexpParserCtxRec_;

typedef void (*RedirCb)(struct CexpParserCtxRec_ *, void *);

106
typedef struct CexpParserCtxRec_ {
107
	const char		*chpt;
108
109
110
111
	LString			lineStrTbl[10];	/* allow for 10 strings on one line of input  */
	CexpSymRec		rval_sym;       /* return value and status of last evaluation */
	CexpValU		rval;
	int             status;         
112
	unsigned long	evalInhibit;
113
114
	FILE			*outf;			/* where to print evaluated value			  */
	FILE			*errf;			/* where to print error messages 			  */
115
	char            sbuf[1000];		/* scratch space for strings                  */
116
117
118
119
120
121
122
	FILE            *o_stdout;      /* redirection */
	FILE            *o_stderr;      /* redirection */
	FILE            *o_stdin;       /* redirection */
	FILE            *o_outf;
	FILE            *o_errf;
	RedirCb         redir_cb;
	void            *cb_arg;
123
124
} CexpParserCtxRec;

125
static CexpSym
126
varCreate(CexpParserCtx ctx, char *name, CexpType type)
127
{
128
CexpSym rval;
129
	if (!(rval=cexpVarLookup(name,1)/*allow creation*/)) {
130
131
		if ( ctx->errf )
			fprintf(ctx->errf, "unable to add new user variable");
132
133
		return 0;
	}
134
	rval->value.type = type;
135
	if (CEXP_TYPE_PTRQ(type))
136
		rval->value.ptv->p=0;
137
	else switch(type) {
138
139
140
141
		case TUChar:	rval->value.ptv->c=0;	break;
		case TUShort:	rval->value.ptv->s=0;	break;
		case TUInt:		rval->value.ptv->i=0;	break;
		case TULong:	rval->value.ptv->l=0;	break;
142
143
		case TFloat:	rval->value.ptv->f=0.0;	break;
		case TDouble:	rval->value.ptv->d=0.0;	break;
144
145
146
147
148
149
		default:
			assert(!"unknown type");
	}
	return rval;
}

150
151
152
153
154
155
156
157
158
159
static int
cexpRedir(CexpParserCtx ctx, unsigned long op, void *opath, void *ipath);

static void
cexpUnredir(CexpParserCtx ctx);

/* Redefine so that we can wrap */
#undef yyparse
#define yyparse __cexpparse

160
161
162
163
%}
%pure_parser

%union {
164
165
	CexpTypedValRec				val;
	CexpTypedAddrRec			lval;
166
	CexpTypedAddr				varp;
167
168
	CexpSym						sym;	/* a symbol table entry */
	CexpType					typ;
169
	CexpBinOp					binop;
170
	char						*lstr;	/* string in the line string table */
strauman's avatar
strauman committed
171
	struct			{
172
173
		CexpTypedAddrRec	lval;
		CexpBinOp			op;
174
	}							fixexp;
175
176
177
178
	struct			{
		CexpSym				sym;
		char				*mname;		/* string kept in the line string table */
	}							method;
179
	unsigned long				ul;
180
	char                        *chrp;
181
182
}

183
184
%token <val>	NUMBER
%token <val>    STR_CONST
185
186
%token <sym>	FUNC VAR UVAR
%token <lstr>	IDENT		/* an undefined identifier */
187
188
%token			KW_CHAR		/* keyword 'char' */
%token			KW_SHORT	/* keyword 'short' */
189
%token			KW_INT		/* keyword 'int' */
190
%token			KW_LONG		/* keyword 'long' */
191
192
%token			KW_FLOAT	/* keyword 'float' */
%token			KW_DOUBLE	/* keyword 'double' */
193
%token <binop>	MODOP		/* +=, -= & friends */
194
195
196
197
%token <ul>     REDIR
%token <ul>     REDIRBOTH
%token <ul>     REDIRAPPEND
%token <ul>     REDIRAPPENDBOTH
198

199
%type  <varp>	nonfuncvar
200
%type  <varp>	anyvar
201
%type  <chrp>   redirarg
202
%type  <val>	def redef newdef line
203
%type  <val>	commaexp
204
205
%type  <val>	exp
%type  <val>	binexp
206
207
%type  <ul>		or
%type  <ul>		and
208
%type  <val>	unexp
209
%type  <fixexp> postfix prefix
210
%type  <lval>	lval
211
212
%type  <val>	call
%type  <val>	funcp
213
%type  <val>	castexp
214
%type  <method> symmethod
215
%type  <ul>     oredirop
216

217
%type  <typ>	fpcast pcast cast typeid fptype
218

strauman's avatar
strauman committed
219
%nonassoc	NONE
220
%left		','
strauman's avatar
strauman committed
221
%right		'?' ':'
222
%right		'=' MODOP
strauman's avatar
strauman committed
223
224
225
226
227
228
229
230
231
232
%left		OR
%left		AND
%left		'|'
%left		'^'
%left		'&'
%left		EQ NE
%left		'<' '>' LE GE
%left		SHL SHR
%left		'-' '+'
%left		'*' '/' '%'
233
234
235
236
%right		CAST
%right		VARCAST
%right		DEREF
%right		ADDR
strauman's avatar
strauman committed
237
%right		PREFIX
238
239
240
241
242
%left		MM
%left		PP
%right		NEG
%right		'~'
%right		'!'
strauman's avatar
strauman committed
243
%left		CALL
244
%left		'.'
245

246
247
%parse-param {CexpParserCtx ctx}

248
249
%%

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
input:	redir line	{ if ( TVoid != $2.type ) { ctx->rval=$2.tv; ctx->rval_sym.value.type = $2.type; } ctx->status = 0; YYACCEPT; }
;

oredirop: '>'
		{ $$=REDIR; }
	|	SHR
		{ $$=REDIRAPPEND; }
	|	'>' '&'
		{ $$=REDIRBOTH; }
	|	SHR '&'
		{ $$=REDIRAPPENDBOTH; }
;

redirarg: nonfuncvar ':'
		{
			if ( TUCharP != $1->type ) {
				errmsg(ctx, "(bad type): redirector requires string argument\n");
				YYERROR;
			}
			$$ = $1->ptv->p;
		}
	|     STR_CONST  ':'
		{
			$$ = $1.tv.p;
		}
;

redir:  /* nothing */
	|  oredirop redirarg
		{ if ( cexpRedir( ctx, $1, $2,  0 ) ) YYERROR; }
	|  '<'      redirarg
		{ if ( cexpRedir( ctx,  0,  0, $2 ) ) YYERROR; }
	|  '<'      redirarg  oredirop redirarg
		{ if ( cexpRedir( ctx, $3, $4, $2 ) ) YYERROR; }
	|  oredirop redirarg  '<'      redirarg
		{ if ( cexpRedir( ctx, $1, $2, $4 ) ) YYERROR; }
286
;
287

288
289
290
291
292
293
redef:	typeid anyvar
					{ EVAL($2->type = $1;); CHECK(cexpTA2TV(&$$,$2)); }
	| 	typeid '*' anyvar
					{ EVAL($3->type = CEXP_TYPE_BASE2PTR($1);); CHECK(cexpTA2TV(&$$,$3)); }
	| 	fptype '(' '*' anyvar ')' '(' ')'
					{ EVAL($4->type = $1); CHECK(cexpTA2TV(&$$,$4)); }
294
295
296
;

newdef: typeid IDENT
297
					{ CexpSym found;
298
					  EVAL(if (!(found = varCreate(ctx, $2, $1))) YYERROR; \
299
					  		CHECK(cexpTA2TV(&$$,&found->value)) );
300
301
					}
	| 	typeid '*' IDENT
302
					{ CexpSym found;
303
					  EVAL(if (!(found = varCreate(ctx, $3, CEXP_TYPE_BASE2PTR($1)))) YYERROR; \
304
					  		CHECK(cexpTA2TV(&$$,&found->value)));
305
306
					}
	| 	fptype '(' '*' IDENT ')' '(' ')'
307
					{ CexpSym found;
308
					  EVAL(if (!(found = varCreate(ctx, $4, $1))) YYERROR; \
309
					  		CHECK(cexpTA2TV(&$$,&found->value)));
310
311
312
					}
;

313
314
315
def: newdef | redef '!'
;

316
317
318
commaexp:	exp
	|	commaexp ',' exp
					{ $$=$3; }
319
320
;

321
line:	'\n'
322
					{	$$.type=TVoid; }
323
324
	|	IDENT '\n'
					{
325
						$$.type=TVoid;
326
						yyerror(ctx, "unknown symbol/variable; '=' expected");
327
328
						YYERROR;
					}
329
330
	|	def '\n'
	|   redef '\n'	{
331
						errmsg(ctx, ": symbol already defined; append '!' to enforce recast\n");
332
333
						YYERROR;
					}
334
	|	commaexp '\n'
335
					{FILE *f=ctx->outf;
till's avatar
till committed
336
						$$=$1;
337
338
						if (CEXP_TYPE_FPQ($1.type)) {
							CHECK(cexpTypeCast(&$1,TDouble,0));
till's avatar
till committed
339
340
							if (f)
								fprintf(f,"%f\n",$1.tv.d);
341
						}else {
342
343
							if (TUChar==$1.type) {
								unsigned char c=$1.tv.c,e=0;
till's avatar
till committed
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
								if (f) {
									fprintf(f,"0x%02x (%d)",c,c);
									switch (c) {
										case 0:	    e=1; c='0'; break;
										case '\t':	e=1; c='t'; break;
										case '\r':	e=1; c='r'; break;
										case '\n':	e=1; c='n'; break;
										case '\f':	e=1; c='f'; break;
										default: 	break;
									}
									if (isprint(c)) {
										fputc('\'',f);
										if (e) fputc('\\',f);
										fputc(c,f);
										fputc('\'',f);
									}
									fputc('\n',f);
361
362
363
								}
							} else {
								CHECK(cexpTypeCast(&$1,TULong,0));
till's avatar
till committed
364
								if (f)
365
									fprintf(f,"0x%0*lx (%ld)\n",(int)(2*sizeof($1.tv.l)), $1.tv.l, $1.tv.l);
366
							}
367
368
						}
					}
369
370
;

371
exp:	binexp 
372
	|   lval  '=' exp
373
					{ $$=$3; EVAL(CHECK(cexpTVAssign(&$1, &$3))); }
374
	|   lval  MODOP	exp
375
376
377
378
379
380
					{ EVAL( \
						CHECK(cexpTA2TV(&$$,&$1)); \
						CHECK(cexpTVBinOp(&$$, &$$, &$3, $2)); \
						CHECK(cexpTVAssign(&$1,&$$)); \
					  );
					}
381
	|   IDENT '=' exp
382
					{ CexpSym found;
383
					  $$=$3; EVAL(if (!(found=varCreate(ctx, $1, $3.type))) {	\
384
385
									YYERROR; 								\
								}\
386
								CHECK(cexpTVAssign(&found->value, &$3)); );
387
					}
388
389
;

390
binexp:	castexp
391
	|	or  binexp	%prec OR
392
393
394
					{ $$.tv.l = $1 || cexpTVTrueQ(&$2);
					  $$.type = TULong;
					  POPEVAL; }
395
	|	and binexp	%prec AND
396
397
398
					{ $$.tv.l = $1 && cexpTVTrueQ(&$2);
					  $$.type = TULong;
					  POPEVAL; }
399
	|	binexp '|' binexp
400
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OOr)); }
401
	|	binexp '^' binexp
402
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OXor)); }
403
	|	binexp '&' binexp
404
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OAnd)); }
405
	|	binexp NE binexp
406
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,ONe)); }
407
	|	binexp EQ binexp
408
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OEq)); }
409
	|	binexp '>' binexp
410
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OGt)); }
411
	|	binexp '<' binexp
412
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OLt)); }
413
	|	binexp LE binexp
414
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OLe)); }
415
	|	binexp GE binexp
416
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OGe)); }
417
	|	binexp SHL binexp
418
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OShL)); }
419
	|	binexp SHR binexp
420
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OShR)); }
421
	|	binexp '+' binexp
422
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OAdd)); }
423
	|	binexp '-' binexp
424
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OSub)); }
425
	|	binexp '*' binexp
426
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OMul)); }
427
	|	binexp '/' binexp
428
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,ODiv)); }
429
	|	binexp '%' binexp
430
					{ CHECK(cexpTVBinOp(&$$,&$1,&$3,OMod)); }
431
432
;

433
or:		binexp OR
434
					{ $$=cexpTVTrueQ(&$1); PSHEVAL($$); }
435
;
436
437
	
and:	binexp AND
438
					{ $$=cexpTVTrueQ(&$1); PSHEVAL( ! $$); }
439
;
strauman's avatar
strauman committed
440

441
442
prefix:	MM lval	%prec PREFIX
					{ $$.lval=$2; $$.op=OSub; }
strauman's avatar
strauman committed
443
	|	PP lval %prec PREFIX
444
					{ $$.lval=$2; $$.op=OAdd; }
strauman's avatar
strauman committed
445
446
;

447
	
448
449
postfix: lval MM
					{ $$.lval=$1; $$.op=OSub; }
strauman's avatar
strauman committed
450
	|	lval PP
451
					{ $$.lval=$1; $$.op=OAdd; }
strauman's avatar
strauman committed
452
	|	lval %prec NONE
453
					{ $$.lval=$1; $$.op=ONoop; }
strauman's avatar
strauman committed
454
;
455

strauman's avatar
strauman committed
456
457
unexp:
/*	VAR
458
					{ CHECK(cexpTVPtrDeref(&$$,&$1->value)); }
strauman's avatar
strauman committed
459
460
*/
		NUMBER
461
	|	STR_CONST
462
463
464
/*
	|	'(' commaexp ')' { $$=$2; }
*/
465
	|	call
strauman's avatar
strauman committed
466
	|	'!' castexp
467
					{ $$.type=TULong; $$.tv.l = ! cexpTVTrueQ(&$2); }
strauman's avatar
strauman committed
468
	|	'~' castexp
469
					{ CHECK(cexpTVUnOp(&$$,&$2,OCpl)); }
strauman's avatar
strauman committed
470
	|	'-' castexp %prec NEG
471
					{ CHECK(cexpTVUnOp(&$$,&$2,ONeg)); }
strauman's avatar
strauman committed
472
/*
473
	|	'*' castexp %prec DEREF
474
					{ CHECK(cexpTVPtrDeref(&$$, &$2)); }
strauman's avatar
strauman committed
475
*/
476
477
	|	'&' nonfuncvar %prec ADDR
					{ CHECK(cexpTVPtr(&$$, $2)); }
478
479
;

480
nonfuncvar: VAR
481
					{ $$=&$1->value; }
482
	|       UVAR		
483
					{ $$=&$1->value; }
484
485
486

anyvar:	nonfuncvar
					{ $$=$1; }
487
488
489
490
	|	FUNC
					{ $$=&$1->value; }
;

491
492
493
lval: 	nonfuncvar  %prec NONE
					{ $$ = *$1; }
	|   '*' castexp %prec DEREF
494
					{ if (!CEXP_TYPE_PTRQ($2.type) || CEXP_TYPE_FUNQ($2.type)) {
495
						yyerror(ctx, "not a valid lval address");
496
497
498
499
500
						YYERROR;
					  }
					  $$.type=CEXP_TYPE_PTR2BASE($2.type);
					  $$.ptv=(CexpVal)$2.tv.p;
					}
strauman's avatar
strauman committed
501
502
/*
	|   	castexp
503
	|	cast VAR %prec CAST
strauman's avatar
strauman committed
504
					{ $$=$2->value; CHECK(cexpTypeCast(&$$,$1,0)); }
strauman's avatar
strauman committed
505
*/
506
507
;

strauman's avatar
strauman committed
508
509
510
511
typeid:	KW_CHAR
					{ $$=TUChar; }
	|	KW_SHORT
					{ $$=TUShort; }
512
513
	|	KW_INT
					{ $$=TUInt; }
strauman's avatar
strauman committed
514
515
	|	KW_LONG
					{ $$=TULong; }
516
517
	|	KW_FLOAT
					{ $$=TFloat; }
strauman's avatar
strauman committed
518
519
	|	KW_DOUBLE
					{ $$=TDouble; }
520
521
;

strauman's avatar
strauman committed
522
cast:	'(' typeid  ')'
523
		%prec CAST	{ $$=$2; }
524
;
525

strauman's avatar
strauman committed
526
527
pcast:
		'(' typeid	'*'	 ')'
528
		%prec CAST	{ $$=CEXP_TYPE_BASE2PTR($2); }
529
;
530

531
532
fptype:	typeid
					{ switch ($1) {
533
						default:
534
							yyerror(ctx, "invalid type for function pointer cast");
535
536
537
538
539
540
						YYERROR;

						case TDouble:
							$$=TDFuncP;
						break;

541
						/* INTFIX */
542
543
544
545
546
547
548
						case TULong:
							$$=TFuncP;
						break;
					  }
					}
;

549
550
551
552
fpcast:
		'(' fptype '(' '*' ')' '(' ')' ')'
					{ $$=$2; }
;
553

554
funcp:	FUNC	
555
					{ $$.type=$1->value.type; $$.tv.p=(void*)$1->value.ptv; }
556
	|	'&' FUNC %prec ADDR
557
					{ $$.type=$2->value.type; $$.tv.p=(void*)$2->value.ptv; }
558
559
	|	postfix
					{ CexpTypedValRec tmp;
560
561
562
563
564
565
566
567
					  EVAL( \
						CHECK(cexpTA2TV(&$$,&$1.lval)); \
						tmp.type=TUChar; \
						tmp.tv.c=1; \
						if (ONoop != $1.op) { \
							CHECK(cexpTVBinOp(&tmp,&$$,&tmp,$1.op)); \
							CHECK(cexpTVAssign(&$1.lval,&tmp)); \
						} \
568
569
570
571
					  );
					}
	|	prefix
					{ CexpTypedValRec tmp;
572
573
574
575
576
577
578
579
					  EVAL( \
						CHECK(cexpTA2TV(&$$,&$1.lval)); \
						tmp.type=TUChar; \
						tmp.tv.c=1; \
						if (ONoop != $1.op) { \
							CHECK(cexpTVBinOp(&$$,&$$,&tmp,$1.op)); \
							CHECK(cexpTVAssign(&$1.lval,&$$)); \
						} \
580
581
					  );
					}
582
583
584
585
586
587
588
589
590
591
;

castexp: unexp
	|	cast	castexp	%prec CAST
					{ $$=$2; CHECK(cexpTypeCast(&$$,$1,CNV_FORCE)); }
	|	pcast	castexp	%prec CAST
					{ $$=$2; CHECK(cexpTypeCast(&$$,$1,CNV_FORCE)); }
	|	fpcast	castexp	%prec CAST
					{ $$=$2; CHECK(cexpTypeCast(&$$,$1,CNV_FORCE)); }
;	
592

593
594
595
596
597
598
599
600
symmethod:
		VAR '.' IDENT { $$.sym = $1; $$.mname=$3; }
	|
		UVAR '.' IDENT { $$.sym = $1; $$.mname=$3; }
	|
		FUNC '.' IDENT { $$.sym = $1; $$.mname=$3; }
;

601

602

603
call:
604
605
		'(' commaexp ')' %prec CALL{ $$=$2; }
	|	funcp
606
	|	symmethod '(' ')'
607
		%prec CALL	{	EVAL(CHECK(cexpSymMember(&$$, $1.sym, $1.mname, (void*)0))); }
608
	|	symmethod '(' exp ')'
609
		%prec CALL	{	EVAL(CHECK(cexpSymMember(&$$, $1.sym, $1.mname, &$3, (void*)0))); }
610
	|	symmethod '(' exp ',' exp ')'
611
		%prec CALL	{	EVAL(CHECK(cexpSymMember(&$$, $1.sym, $1.mname, &$3, &$5, (void*)0))); }
612
	|	call '(' ')'
613
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,(void*)0))); }
614
	|	call '(' exp ')'
615
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,(void*)0))); }
616
	| 	call '(' exp ',' exp ')'
617
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,(void*)0))); }
618
	|	call '(' exp ',' exp ',' exp  ')'
619
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,(void*)0))); }
620
	|	call '(' exp ',' exp ',' exp  ',' exp  ')'
621
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,(void*)0))); }
622
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ')'
623
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,(void*)0))); }
624
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ')'
625
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,(void*)0))); }
626
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ')'
627
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,&$15,(void*)0))); }
628
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ')'
629
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,&$15,&$17,(void*)0))); }
630
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ')'
631
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,&$15,&$17,&$19,(void*)0))); }
632
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ')'
633
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,&$15,&$17,&$19,&$21,(void*)0))); }
634
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp ',' exp  ')'
635
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,&$15,&$17,&$19,&$21,&$23,(void*)0))); }
636
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp ',' exp ',' exp  ')'
637
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,&$15,&$17,&$19,&$21,&$23,&$25,(void*)0))); }
638
	|	call '(' exp ',' exp ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp  ',' exp ',' exp ',' exp ',' exp  ')'
639
		%prec CALL	{	EVAL(CHECK(cexpTVFnCall(&$$,&$1,&$3,&$5,&$7,&$9,&$11,&$13,&$15,&$17,&$19,&$21,&$23,&$25,&$27,(void*)0))); }
640
641
;

642
	
643
644
645
%%


646
647
648
/* add a string to the line string table returning its index
 * RETURNS a negative number on error
 */
649
LString
650
lstAddString(CexpParserCtx env, char *string)
651
{
652
653
LString			rval=0;
LString			*chppt;
654
655
656
657
658
659
660
661
662
int				i;
	for (i=0,chppt=env->lineStrTbl;
		 i<sizeof(env->lineStrTbl)/sizeof(env->lineStrTbl[0]);
		 i++,chppt++) {
		if (*chppt) {
			if  (strcmp(string,*chppt))			continue;
			else /* string exists already */	return *chppt;
		}
		/* string exists already */
663
		if ((rval=malloc(strlen(string)+1))) {
664
			*chppt=rval;
665
			strcpy(rval,string);
666
			return (LString) rval;
667
668
		}
	}
669
670
	if ( env->errf )
		fprintf(env->errf,"Cexp: Line String Table exhausted\n");
671
	return 0;
672
}
673

674
#define ch ((int)(*pa->chpt))
675
676
#define getch() do { (pa->chpt)++;} while(0)

677
678
/* helper to save typing */
static int
679
prerr(CexpParserCtx ctx)
680
{
681
	errmsg(ctx, "(yylex): buffer overflow\n");
682
683
684
685
	return LEXERR;
}

static int
686
scanfrac(char *buf, char *chpt, int size, YYSTYPE *rval, CexpParserCtx pa, int rejectLonely)
687
688
689
690
691
{
int hasE=0;
	/* first, we put ch to the buffer */
	*(chpt++)=(char)ch; size--; /* assume it's still safe */
	getch();
692
693
694
	if ( isdigit(ch) || 'E' == toupper(ch) ) {
		do {
			while(isdigit(ch) && size) {
695
				*(chpt++)=(char)ch; if (!--size) return prerr(pa);
696
697
				getch();
			}
698
			if (toupper(ch)=='E' && !hasE) {
699
				*(chpt++)=(char)'E'; if (!--size) return prerr(pa);
700
701
				getch();
				if ('-'==ch || '+'==ch) {
702
					*(chpt++)=(char)ch; if (!--size) return prerr(pa);
703
704
705
706
707
708
709
710
711
712
713
					getch();
				}
				hasE=1;
			} else {
		break; /* the loop */
			}
		} while (1);
	} else {
		if ( rejectLonely )
			return '.';
	}
714
715
716
717
718
719
	*chpt=0;
	rval->val.type=TDouble;
	rval->val.tv.d=strtod(buf,&chpt);
	return *chpt ? LEXERR : NUMBER;
}

720
int
721
yylex(YYSTYPE *rval, CexpParserCtx pa)
722
{
723
724
725
unsigned long num;
int           limit=sizeof(pa->sbuf)-1;
char          *chpt;
726
727
728
729

	while (' '==ch || '\t'==ch)
		getch();

730
	if (isdigit(ch) || '\''==ch) {
731
732
		/* a number */
		num=0;
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749

		if ('\''==ch) {
			/* char constant */
			getch();
			num=ch;
			if ('\\'==ch) {
				getch();
				/* escape sequence */
				switch (ch) {
					case 't': num='\t'; break;
					case 'n': num='\n'; break;
					case 'r': num='\r'; break;
					case '0': num=0;	break;
					case 'f': num='\f';	break;
					case '\\': num='\\';break;
					case '\'': num='\'';break;
					default:
750
						wrnmsg(pa, ": unknown escape sequence, using unescaped char\n");
751
752
753
754
755
756
						num=ch;
					break;
				}
			}
			getch();
			if ('\''!=ch)
757
				wrnmsg(pa, ": missing closing '\n");
758
759
			else
				getch();
strauman's avatar
strauman committed
760
			rval->val.tv.c=(unsigned char)num;
761
762
763
			rval->val.type=TUChar;
			return NUMBER;
		}
764
		chpt=pa->sbuf;
765
		if ('0'==ch) {
766
767
768
			
			/* hex, octal or fractional */
			*(chpt++)=(char)ch; limit--;
769
770
771
772
773
774
775
776
777
778
779
			getch();
			if ('x'==ch) {
				/* a hex number */
				getch();
				while (isxdigit(ch)) {
					num<<=4;
					if (ch>='a')		num+=ch-'a'+10;
					else if (ch>='A')	num+=ch-'A'+10;
					else				num+=ch-'0';
					getch();
				}
780
781
			} else if ('.'==ch) {
				/* a decimal number */
782
				return scanfrac(pa->sbuf,chpt,limit,rval,pa,0);
783
784
785
786
787
788
789
790
791
792
793
			} else {
				/* OK, it's octal */
				while ('0'<=ch && ch<'8') {
					num<<=3;
					num+=ch-'0';
					getch();
				}
			}
		} else {
			/* so it must be base 10 */
			do {
794
				*(chpt++)=(char)ch; limit--;
795
796
				num=10*num+(ch-'0');
				getch();
797
798
			} while (isdigit(ch) && limit);
			if (!limit) {
799
				return prerr(pa);
800
801
802
			}
			if ('.'==ch) {
				/* it's a fractional number */
803
				return scanfrac(pa->sbuf,chpt,limit,rval,pa,0);
804
			}
805
		}
806
807
		rval->val.tv.l=num;
		rval->val.type=TULong;
808
		return NUMBER;
809
	} else if ('.'==ch) {
810
811
		/* perhaps also a fractional number */
		return
812
			scanfrac(pa->sbuf,pa->sbuf,limit,rval,pa,1);
813
	} else if (isalpha(ch) || ISIDENTCHAR(ch)) {
814
		/* slurp in an identifier */
815
		chpt=pa->sbuf;
816
817
818
		do {
			*(chpt++)=ch;
			getch();
819
		} while ((isalnum(ch)||ISIDENTCHAR(ch)) && (--limit > 0));
820
		*chpt=0;
821
		if (!limit)
822
			return prerr(pa);
823
		/* is it one of the type cast keywords? */
824
		if (!strcmp(pa->sbuf,"char"))
825
			return KW_CHAR;
826
		else if (!strcmp(pa->sbuf,"short"))
827
			return KW_SHORT;
828
829
		else if (!strcmp(pa->sbuf,"int"))
			return KW_INT;
830
		else if (!strcmp(pa->sbuf,"long"))
831
			return KW_LONG;
832
		else if (!strcmp(pa->sbuf,"float"))
833
			return KW_FLOAT;
834
		else if (!strcmp(pa->sbuf,"double"))
835
			return KW_DOUBLE;
836
		else if ((rval->sym=cexpSymLookup(pa->sbuf, 0)))
837
			return CEXP_TYPE_FUNQ(rval->sym->value.type) ? FUNC : VAR;
838
		else if ((rval->sym=cexpVarLookup(pa->sbuf,0))) {
839
			return UVAR;
840
		}
841
842

		/* it's a currently undefined symbol */
843
		return (rval->lstr=lstAddString(pa,pa->sbuf)) ? IDENT : LEXERR;
844
	} else if ('"'==ch) {
845
		/* generate a string constant */
846
		char *dst;
847
		const char *strStart;
848
		dst=pa->sbuf-1;
849
		strStart = pa->chpt+1;
850
		do {
851
852
		skipit:	
			dst++; limit--;
853
			getch();
854
			*dst=ch;
855
			if ('\\'==ch) {
856
857
				getch();
				switch (ch) {
858
859
860
861
862
863
					case 'n':	*dst='\n'; goto skipit;
					case 'r':	*dst='\r'; goto skipit;
					case 't':	*dst='\t'; goto skipit;
					case '"':	*dst='"';  goto skipit;
					case '\\':	           goto skipit;
					case '0':	*dst=0;    goto skipit;
864
					default:
865
						dst++; limit--; *dst=ch;
866
867
868
						break;
				}
			}
869
870
			if ('"'==ch) {
				*dst=0;
871
				getch();
872
				rval->val.type=TUCharP;
873
#ifdef CONFIG_STRINGS_LIVE_FOREVER
874
				rval->val.tv.p=cexpStrLookup(pa->sbuf,1);
875
#else
876
				rval->val.tv.p=lstAddString(pa,pa->sbuf);
877
878
#endif
				return rval->val.tv.p ? STR_CONST : LEXERR;
879
880
			}
		} while (ch && limit>2);
881
		return LEXERR_INCOMPLETE_STRING - (pa->chpt - strStart);
882
	} else {
883
884
885
		long rv=ch;
		if (rv) getch();

886
887
888
889
890
891
892
893
894
		/* comments? skip the rest of the line */
		if ('#'==rv || ('/'==ch && '/'==rv)) {
			while (ch && '\n'!=rv) {
				rv=ch;
				getch();
			}
			return '\n';
		}

895
896
897
		/* it's any kind of 'special' character such as
		 * an operator etc.
		 */
898
899
900
901
902

		/* check for 'double' character operators '&&' '||' '<<' '>>' '==' '!=' '<=' '>=' */
		switch (ch) { /* the second character */
			default: break;

strauman's avatar
strauman committed
903
904
905
			case '+': if ('+'==rv) rv=PP;  break;
			case '-': if ('-'==rv) rv=MM;  break;

906
907
908
909
910
911
			case '&': if ('&'==rv) rv=AND; break;
			case '|': if ('|'==rv) rv=OR;  break;

			case '<': if ('<'==rv) rv=SHL; break;
			case '>': if ('>'==rv) rv=SHR; break;

912

913
914
915
916
917
918
919
			case '=':
				switch (rv) {
					default: break;
					case '=': rv=EQ;	break;
					case '!': rv=NE;	break;
					case '<': rv=LE;	break;
					case '>': rv=GE;	break;
920
921
922
923
924
925
926
927
					case '+': rv=MODOP; rval->binop=OAdd;	break;
					case '-': rv=MODOP; rval->binop=OSub;	break;
					case '*': rv=MODOP; rval->binop=OMul;	break;
					case '/': rv=MODOP; rval->binop=ODiv;	break;
					case '%': rv=MODOP; rval->binop=OMod;	break;
					case '&': rv=MODOP; rval->binop=OAnd;	break;
					case '^': rv=MODOP; rval->binop=OXor;	break;
					case '|': rv=MODOP; rval->binop=OOr;	break;
928
929
930
931
				}
			break;
		}
		if (rv>255) getch(); /* skip second char */
932
		/* yyparse cannot deal with '\0' chars, so we translate it back to '\n'...*/
933
934
		if ((SHL==rv || SHR==rv) && '=' == ch) {
			getch();
935
			rval->binop = (SHL==rv ? OShL : OShR);
936
937
			rv=MODOP;
		}
938
939
		return rv ? rv : '\n';
	}
940
	return 0; /* seems to mean ERROR/EOF */
941
942
}

943
944
945
/* re-initialize a parser context to parse 'buf';
 * If called with a NULL argument, a new
 * context is created and initialized.
till's avatar
till committed
946
 *
947
948
949
950
951
952
953
954
 * RETURNS: initialized context
 */

static void
releaseStrings(CexpParserCtx ctx)
{
int			i;
char		**chppt;
955

956
	/* release the line string table */
957
958
959
	for (i=0,chppt=ctx->lineStrTbl;
		 i<sizeof(ctx->lineStrTbl)/sizeof(ctx->lineStrTbl[0]);
		 i++,chppt++) {
960
961
962
963
964
965
966
967
		if (*chppt) {
			free(*chppt);
			*chppt=0;
		}
	}
}

CexpParserCtx
968
cexpCreateParserCtx(FILE *outf, FILE *errf, RedirCb redir_cb, void *uarg)
969
970
{
CexpParserCtx	ctx=0;
971

till's avatar
till committed
972
973
	assert(ctx=(CexpParserCtx)malloc(sizeof(*ctx)));
	memset(ctx,0,sizeof(*ctx));
974
975
	ctx->rval_sym.value.type = TULong;
	ctx->rval.l              = 0;
976
977
978
979
980
	ctx->rval_sym.value.ptv  = &ctx->rval;
	ctx->rval_sym.name       = CEXP_LAST_RESULT_VAR_NAME;
	ctx->rval_sym.size       = sizeof(ctx->rval);
	ctx->rval_sym.flags      = 0;
	ctx->rval_sym.help       = "value of last evaluated expression";
981
982
983
984
985
986
987
988
989
990
991
	ctx->outf                = outf;
	ctx->errf                = errf;
	ctx->status              = -1;
	ctx->o_stdout            = 0;
	ctx->o_stderr            = 0;
	ctx->o_stdin             = 0;
	ctx->o_outf              = 0;
	ctx->o_errf              = 0;
	ctx->redir_cb            = redir_cb;
	ctx->cb_arg              = uarg;

992
993
994
	return ctx;
}

995
void
996
cexpResetParserCtx(CexpParserCtx ctx, const char *buf)
997
998
999
{
	ctx->chpt=buf;
	ctx->evalInhibit=0;
1000
	ctx->status = -1;
For faster browsing, not all history is shown. View entire blame