GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/bc/bc.y Lines: 158 242 65.3 %
Date: 2017-11-07 Branches: 78 150 52.0 %

Line Branch Exec Source
1
%{
2
/*	$OpenBSD: bc.y,v 1.51 2017/07/02 23:19:07 deraadt Exp $	*/
3
4
/*
5
 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
/*
21
 * This implementation of bc(1) uses concepts from the original 4.4
22
 * BSD bc(1). The code itself is a complete rewrite, based on the
23
 * Posix defined bc(1) grammar. Other differences include type safe
24
 * usage of pointers to build the tree of emitted code, typed yacc
25
 * rule values, dynamic allocation of all data structures and a
26
 * completely rewritten lexical analyzer using lex(1).
27
 *
28
 * Some effort has been made to make sure that the generated code is
29
 * the same as the code generated by the older version, to provide
30
 * easy regression testing.
31
 */
32
33
#include <sys/types.h>
34
#include <sys/wait.h>
35
36
#include <ctype.h>
37
#include <err.h>
38
#include <errno.h>
39
#include <histedit.h>
40
#include <limits.h>
41
#include <search.h>
42
#include <signal.h>
43
#include <stdarg.h>
44
#include <string.h>
45
#include <unistd.h>
46
47
#include "extern.h"
48
#include "pathnames.h"
49
50
#define END_NODE	((ssize_t) -1)
51
#define CONST_STRING	((ssize_t) -2)
52
#define ALLOC_STRING	((ssize_t) -3)
53
54
struct tree {
55
	ssize_t			index;
56
	union {
57
		char		*astr;
58
		const char	*cstr;
59
	} u;
60
};
61
62
int			yyparse(void);
63
int			yywrap(void);
64
65
int			fileindex;
66
int			sargc;
67
char			**sargv;
68
char			*filename;
69
char			*cmdexpr;
70
71
static void		grow(void);
72
static ssize_t		cs(const char *);
73
static ssize_t		as(const char *);
74
static ssize_t		node(ssize_t, ...);
75
static void		emit(ssize_t, int);
76
static void		emit_macro(int, ssize_t);
77
static void		free_tree(void);
78
static ssize_t		numnode(int);
79
static ssize_t		lookup(char *, size_t, char);
80
static ssize_t		letter_node(char *);
81
static ssize_t		array_node(char *);
82
static ssize_t		function_node(char *);
83
84
static void		add_par(ssize_t);
85
static void		add_local(ssize_t);
86
static void		warning(const char *);
87
static void		init(void);
88
static __dead void	usage(void);
89
static char		*escape(const char *);
90
91
static ssize_t		instr_sz = 0;
92
static struct tree	*instructions = NULL;
93
static ssize_t		current = 0;
94
static int		macro_char = '0';
95
static int		reset_macro_char = '0';
96
static int		nesting = 0;
97
static int		breakstack[16];
98
static int		breaksp = 0;
99
static ssize_t		prologue;
100
static ssize_t		epilogue;
101
static bool		st_has_continue;
102
static char		str_table[UCHAR_MAX][2];
103
static bool		do_fork = true;
104
static u_short		var_count;
105
static pid_t		dc;
106
107
extern char *__progname;
108
109
#define BREAKSTACK_SZ	(sizeof(breakstack)/sizeof(breakstack[0]))
110
111
/* These values are 4.4BSD bc compatible */
112
#define FUNC_CHAR	0x01
113
#define ARRAY_CHAR	0xa1
114
115
/* Skip '\0', [, \ and ] */
116
#define ENCODE(c)	((c) < '[' ? (c) : (c) + 3);
117
#define VAR_BASE	(256-4)
118
#define MAX_VARIABLES	(VAR_BASE * VAR_BASE)
119
120
%}
121
122
%start program
123
124
%union {
125
	ssize_t		node;
126
	struct lvalue	lvalue;
127
	const char	*str;
128
	char		*astr;
129
}
130
131
%token COMMA SEMICOLON LPAR RPAR LBRACE RBRACE LBRACKET RBRACKET DOT
132
%token NEWLINE
133
%token <astr> LETTER
134
%token <str> NUMBER STRING
135
%token DEFINE BREAK QUIT LENGTH
136
%token RETURN FOR IF WHILE SQRT
137
%token SCALE IBASE OBASE AUTO
138
%token CONTINUE ELSE PRINT
139
140
%left BOOL_OR
141
%left BOOL_AND
142
%nonassoc BOOL_NOT
143
%nonassoc EQUALS LESS_EQ GREATER_EQ UNEQUALS LESS GREATER
144
%right <str> ASSIGN_OP
145
%left PLUS MINUS
146
%left MULTIPLY DIVIDE REMAINDER
147
%right EXPONENT
148
%nonassoc UMINUS
149
%nonassoc INCR DECR
150
151
%type <lvalue>	named_expression
152
%type <node>	argument_list
153
%type <node>	alloc_macro
154
%type <node>	expression
155
%type <node>	function
156
%type <node>	function_header
157
%type <node>	input_item
158
%type <node>	opt_argument_list
159
%type <node>	opt_expression
160
%type <node>	opt_relational_expression
161
%type <node>	opt_statement
162
%type <node>	print_expression
163
%type <node>	print_expression_list
164
%type <node>	relational_expression
165
%type <node>	return_expression
166
%type <node>	semicolon_list
167
%type <node>	statement
168
%type <node>	statement_list
169
170
%%
171
172
program		: /* empty */
173
		| program input_item
174
		;
175
176
input_item	: semicolon_list NEWLINE
177
			{
178
				emit($1, 0);
179
				macro_char = reset_macro_char;
180
				putchar('\n');
181
				free_tree();
182
				st_has_continue = false;
183
			}
184
		| function
185
			{
186
				putchar('\n');
187
				free_tree();
188
				st_has_continue = false;
189
			}
190
		| error NEWLINE
191
			{
192
				yyerrok;
193
			}
194
		| error QUIT
195
			{
196
				yyerrok;
197
			}
198
		;
199
200
semicolon_list	: /* empty */
201
			{
202
				$$ = cs("");
203
			}
204
		| statement
205
		| semicolon_list SEMICOLON statement
206
			{
207
				$$ = node($1, $3, END_NODE);
208
			}
209
		| semicolon_list SEMICOLON
210
		;
211
212
statement_list	: /* empty */
213
			{
214
				$$ = cs("");
215
			}
216
		| statement
217
		| statement_list NEWLINE
218
		| statement_list NEWLINE statement
219
			{
220
				$$ = node($1, $3, END_NODE);
221
			}
222
		| statement_list SEMICOLON
223
		| statement_list SEMICOLON statement
224
			{
225
				$$ = node($1, $3, END_NODE);
226
			}
227
		;
228
229
230
opt_statement	: /* empty */
231
			{
232
				$$ = cs("");
233
			}
234
		| statement
235
		;
236
237
statement	: expression
238
			{
239
				$$ = node($1, cs("ps."), END_NODE);
240
			}
241
		| named_expression ASSIGN_OP expression
242
			{
243
				if ($2[0] == '\0')
244
					$$ = node($3, cs($2), $1.store,
245
					    END_NODE);
246
				else
247
					$$ = node($1.load, $3, cs($2), $1.store,
248
					    END_NODE);
249
			}
250
		| STRING
251
			{
252
				$$ = node(cs("["), as($1),
253
				    cs("]P"), END_NODE);
254
			}
255
		| BREAK
256
			{
257
				if (breaksp == 0) {
258
					warning("break not in for or while");
259
					YYERROR;
260
				} else {
261
					$$ = node(
262
					    numnode(nesting -
263
						breakstack[breaksp-1]),
264
					    cs("Q"), END_NODE);
265
				}
266
			}
267
		| CONTINUE
268
			{
269
				if (breaksp == 0) {
270
					warning("continue not in for or while");
271
					YYERROR;
272
				} else {
273
					st_has_continue = true;
274
					$$ = node(numnode(nesting -
275
					    breakstack[breaksp-1] - 1),
276
					    cs("J"), END_NODE);
277
				}
278
			}
279
		| QUIT
280
			{
281
				sigset_t mask;
282
283
				putchar('q');
284
				fflush(stdout);
285
				if (dc) {
286
					sigprocmask(SIG_BLOCK, NULL, &mask);
287
					sigsuspend(&mask);
288
				} else
289
					exit(0);
290
			}
291
		| RETURN return_expression
292
			{
293
				if (nesting == 0) {
294
					warning("return must be in a function");
295
					YYERROR;
296
				}
297
				$$ = $2;
298
			}
299
		| FOR LPAR alloc_macro opt_expression SEMICOLON
300
		     opt_relational_expression SEMICOLON
301
		     opt_expression RPAR opt_statement pop_nesting
302
			{
303
				ssize_t n;
304
305
				if (st_has_continue)
306
					n = node($10, cs("M"), $8, cs("s."),
307
					    $6, $3, END_NODE);
308
				else
309
					n = node($10, $8, cs("s."), $6, $3,
310
					    END_NODE);
311
312
				emit_macro($3, n);
313
				$$ = node($4, cs("s."), $6, $3, cs(" "),
314
				    END_NODE);
315
			}
316
		| IF LPAR alloc_macro pop_nesting relational_expression RPAR
317
		      opt_statement
318
			{
319
				emit_macro($3, $7);
320
				$$ = node($5, $3, cs(" "), END_NODE);
321
			}
322
		| IF LPAR alloc_macro pop_nesting relational_expression RPAR
323
		      opt_statement ELSE alloc_macro pop_nesting opt_statement
324
			{
325
				emit_macro($3, $7);
326
				emit_macro($9, $11);
327
				$$ = node($5, $3, cs("e"), $9, cs(" "),
328
				    END_NODE);
329
			}
330
		| WHILE LPAR alloc_macro relational_expression RPAR
331
		      opt_statement pop_nesting
332
			{
333
				ssize_t n;
334
335
				if (st_has_continue)
336
					n = node($6, cs("M"), $4, $3, END_NODE);
337
				else
338
					n = node($6, $4, $3, END_NODE);
339
				emit_macro($3, n);
340
				$$ = node($4, $3, cs(" "), END_NODE);
341
			}
342
		| LBRACE statement_list RBRACE
343
			{
344
				$$ = $2;
345
			}
346
		| PRINT print_expression_list
347
			{
348
				$$ = $2;
349
			}
350
		;
351
352
alloc_macro	: /* empty */
353
			{
354
				$$ = cs(str_table[macro_char]);
355
				macro_char++;
356
				/* Do not use [, \ and ] */
357
				if (macro_char == '[')
358
					macro_char += 3;
359
				/* skip letters */
360
				else if (macro_char == 'a')
361
					macro_char = '{';
362
				else if (macro_char == ARRAY_CHAR)
363
					macro_char += 26;
364
				else if (macro_char == 255)
365
					fatal("program too big");
366
				if (breaksp == BREAKSTACK_SZ)
367
					fatal("nesting too deep");
368
				breakstack[breaksp++] = nesting++;
369
			}
370
		;
371
372
pop_nesting	: /* empty */
373
			{
374
				breaksp--;
375
			}
376
		;
377
378
function	: function_header opt_parameter_list RPAR opt_newline
379
		  LBRACE NEWLINE opt_auto_define_list
380
		  statement_list RBRACE
381
			{
382
				int n = node(prologue, $8, epilogue,
383
				    cs("0"), numnode(nesting),
384
				    cs("Q"), END_NODE);
385
				emit_macro($1, n);
386
				reset_macro_char = macro_char;
387
				nesting = 0;
388
				breaksp = 0;
389
			}
390
		;
391
392
function_header : DEFINE LETTER LPAR
393
			{
394
				$$ = function_node($2);
395
				free($2);
396
				prologue = cs("");
397
				epilogue = cs("");
398
				nesting = 1;
399
				breaksp = 0;
400
				breakstack[breaksp] = 0;
401
			}
402
		;
403
404
opt_newline	: /* empty */
405
		| NEWLINE
406
		;
407
408
opt_parameter_list
409
		: /* empty */
410
		| parameter_list
411
		;
412
413
414
parameter_list	: LETTER
415
			{
416
				add_par(letter_node($1));
417
				free($1);
418
			}
419
		| LETTER LBRACKET RBRACKET
420
			{
421
				add_par(array_node($1));
422
				free($1);
423
			}
424
		| parameter_list COMMA LETTER
425
			{
426
				add_par(letter_node($3));
427
				free($3);
428
			}
429
		| parameter_list COMMA LETTER LBRACKET RBRACKET
430
			{
431
				add_par(array_node($3));
432
				free($3);
433
			}
434
		;
435
436
437
438
opt_auto_define_list
439
		: /* empty */
440
		| AUTO define_list NEWLINE
441
		| AUTO define_list SEMICOLON
442
		;
443
444
445
define_list	: LETTER
446
			{
447
				add_local(letter_node($1));
448
				free($1);
449
			}
450
		| LETTER LBRACKET RBRACKET
451
			{
452
				add_local(array_node($1));
453
				free($1);
454
			}
455
		| define_list COMMA LETTER
456
			{
457
				add_local(letter_node($3));
458
				free($3);
459
			}
460
		| define_list COMMA LETTER LBRACKET RBRACKET
461
			{
462
				add_local(array_node($3));
463
				free($3);
464
			}
465
		;
466
467
468
opt_argument_list
469
		: /* empty */
470
			{
471
				$$ = cs("");
472
			}
473
		| argument_list
474
		;
475
476
477
argument_list	: expression
478
		| argument_list COMMA expression
479
			{
480
				$$ = node($1, $3, END_NODE);
481
			}
482
		| argument_list COMMA LETTER LBRACKET RBRACKET
483
			{
484
				$$ = node($1, cs("l"), array_node($3),
485
				    END_NODE);
486
				free($3);
487
			}
488
		;
489
490
opt_relational_expression
491
		: /* empty */
492
			{
493
				$$ = cs(" 0 0=");
494
			}
495
		| relational_expression
496
		;
497
498
relational_expression
499
		: expression EQUALS expression
500
			{
501
				$$ = node($1, $3, cs("="), END_NODE);
502
			}
503
		| expression UNEQUALS expression
504
			{
505
				$$ = node($1, $3, cs("!="), END_NODE);
506
			}
507
		| expression LESS expression
508
			{
509
				$$ = node($1, $3, cs(">"), END_NODE);
510
			}
511
		| expression LESS_EQ expression
512
			{
513
				$$ = node($1, $3, cs("!<"), END_NODE);
514
			}
515
		| expression GREATER expression
516
			{
517
				$$ = node($1, $3, cs("<"), END_NODE);
518
			}
519
		| expression GREATER_EQ expression
520
			{
521
				$$ = node($1, $3, cs("!>"), END_NODE);
522
			}
523
		| expression
524
			{
525
				$$ = node($1, cs(" 0!="), END_NODE);
526
			}
527
		;
528
529
530
return_expression
531
		: /* empty */
532
			{
533
				$$ = node(cs("0"), epilogue,
534
				    numnode(nesting), cs("Q"), END_NODE);
535
			}
536
		| expression
537
			{
538
				$$ = node($1, epilogue,
539
				    numnode(nesting), cs("Q"), END_NODE);
540
			}
541
		| LPAR RPAR
542
			{
543
				$$ = node(cs("0"), epilogue,
544
				    numnode(nesting), cs("Q"), END_NODE);
545
			}
546
		;
547
548
549
opt_expression : /* empty */
550
			{
551
				$$ = cs(" 0");
552
			}
553
		| expression
554
		;
555
556
expression	: named_expression
557
			{
558
				$$ = node($1.load, END_NODE);
559
			}
560
		| DOT	{
561
				$$ = node(cs("l."), END_NODE);
562
			}
563
		| NUMBER
564
			{
565
				$$ = node(cs(" "), as($1), END_NODE);
566
			}
567
		| LPAR expression RPAR
568
			{
569
				$$ = $2;
570
			}
571
		| LETTER LPAR opt_argument_list RPAR
572
			{
573
				$$ = node($3, cs("l"),
574
				    function_node($1), cs("x"),
575
				    END_NODE);
576
				free($1);
577
			}
578
		| MINUS expression %prec UMINUS
579
			{
580
				$$ = node(cs(" 0"), $2, cs("-"),
581
				    END_NODE);
582
			}
583
		| expression PLUS expression
584
			{
585
				$$ = node($1, $3, cs("+"), END_NODE);
586
			}
587
		| expression MINUS expression
588
			{
589
				$$ = node($1, $3, cs("-"), END_NODE);
590
			}
591
		| expression MULTIPLY expression
592
			{
593
				$$ = node($1, $3, cs("*"), END_NODE);
594
			}
595
		| expression DIVIDE expression
596
			{
597
				$$ = node($1, $3, cs("/"), END_NODE);
598
			}
599
		| expression REMAINDER expression
600
			{
601
				$$ = node($1, $3, cs("%"), END_NODE);
602
			}
603
		| expression EXPONENT expression
604
			{
605
				$$ = node($1, $3, cs("^"), END_NODE);
606
			}
607
		| INCR named_expression
608
			{
609
				$$ = node($2.load, cs("1+d"), $2.store,
610
				    END_NODE);
611
			}
612
		| DECR named_expression
613
			{
614
				$$ = node($2.load, cs("1-d"),
615
				    $2.store, END_NODE);
616
			}
617
		| named_expression INCR
618
			{
619
				$$ = node($1.load, cs("d1+"),
620
				    $1.store, END_NODE);
621
			}
622
		| named_expression DECR
623
			{
624
				$$ = node($1.load, cs("d1-"),
625
				    $1.store, END_NODE);
626
			}
627
		| named_expression ASSIGN_OP expression
628
			{
629
				if ($2[0] == '\0')
630
					$$ = node($3, cs($2), cs("d"), $1.store,
631
					    END_NODE);
632
				else
633
					$$ = node($1.load, $3, cs($2), cs("d"),
634
					    $1.store, END_NODE);
635
			}
636
		| LENGTH LPAR expression RPAR
637
			{
638
				$$ = node($3, cs("Z"), END_NODE);
639
			}
640
		| SQRT LPAR expression RPAR
641
			{
642
				$$ = node($3, cs("v"), END_NODE);
643
			}
644
		| SCALE LPAR expression RPAR
645
			{
646
				$$ = node($3, cs("X"), END_NODE);
647
			}
648
		| BOOL_NOT expression
649
			{
650
				$$ = node($2, cs("N"), END_NODE);
651
			}
652
		| expression BOOL_AND alloc_macro pop_nesting expression
653
			{
654
				ssize_t n = node(cs("R"), $5, END_NODE);
655
				emit_macro($3, n);
656
				$$ = node($1, cs("d0!="), $3, END_NODE);
657
			}
658
		| expression BOOL_OR alloc_macro pop_nesting expression
659
			{
660
				ssize_t n = node(cs("R"), $5, END_NODE);
661
				emit_macro($3, n);
662
				$$ = node($1, cs("d0="), $3, END_NODE);
663
			}
664
		| expression EQUALS expression
665
			{
666
				$$ = node($1, $3, cs("G"), END_NODE);
667
			}
668
		| expression UNEQUALS expression
669
			{
670
				$$ = node($1, $3, cs("GN"), END_NODE);
671
			}
672
		| expression LESS expression
673
			{
674
				$$ = node($3, $1, cs("("), END_NODE);
675
			}
676
		| expression LESS_EQ expression
677
			{
678
				$$ = node($3, $1, cs("{"), END_NODE);
679
			}
680
		| expression GREATER expression
681
			{
682
				$$ = node($1, $3, cs("("), END_NODE);
683
			}
684
		| expression GREATER_EQ expression
685
			{
686
				$$ = node($1, $3, cs("{"), END_NODE);
687
			}
688
		;
689
690
named_expression
691
		: LETTER
692
			{
693
				$$.load = node(cs("l"), letter_node($1),
694
				    END_NODE);
695
				$$.store = node(cs("s"), letter_node($1),
696
				    END_NODE);
697
				free($1);
698
			}
699
		| LETTER LBRACKET expression RBRACKET
700
			{
701
				$$.load = node($3, cs(";"),
702
				    array_node($1), END_NODE);
703
				$$.store = node($3, cs(":"),
704
				    array_node($1), END_NODE);
705
				free($1);
706
			}
707
		| SCALE
708
			{
709
				$$.load = cs("K");
710
				$$.store = cs("k");
711
			}
712
		| IBASE
713
			{
714
				$$.load = cs("I");
715
				$$.store = cs("i");
716
			}
717
		| OBASE
718
			{
719
				$$.load = cs("O");
720
				$$.store = cs("o");
721
			}
722
		;
723
724
print_expression_list
725
		: print_expression
726
		| print_expression_list COMMA print_expression
727
			{
728
				$$ = node($1, $3, END_NODE);
729
			}
730
731
print_expression
732
		: expression
733
			{
734
				$$ = node($1, cs("ds.n"), END_NODE);
735
			}
736
		| STRING
737
			{
738
				char *p = escape($1);
739
				$$ = node(cs("["), as(p), cs("]n"), END_NODE);
740
				free(p);
741
			}
742
%%
743
744
745
static void
746
grow(void)
747
{
748
	struct tree	*p;
749
	size_t		newsize;
750
751
313306
	if (current == instr_sz) {
752
945
		newsize = instr_sz * 2 + 1;
753
945
		p = reallocarray(instructions, newsize, sizeof(*p));
754
945
		if (p == NULL) {
755
			free(instructions);
756
			err(1, NULL);
757
		}
758
945
		instructions = p;
759
945
		instr_sz = newsize;
760
945
	}
761
156653
}
762
763
static ssize_t
764
cs(const char *str)
765
{
766
93198
	grow();
767
46599
	instructions[current].index = CONST_STRING;
768
46599
	instructions[current].u.cstr = str;
769
46599
	return current++;
770
}
771
772
static ssize_t
773
as(const char *str)
774
{
775
9226
	grow();
776
4613
	instructions[current].index = ALLOC_STRING;
777
4613
	instructions[current].u.astr = strdup(str);
778
4613
	if (instructions[current].u.astr == NULL)
779
		err(1, NULL);
780
4613
	return current++;
781
}
782
783
static ssize_t
784
node(ssize_t arg, ...)
785
{
786
65940
	va_list		ap;
787
	ssize_t		ret;
788
789
32970
	va_start(ap, arg);
790
791
32970
	ret = current;
792
32970
	grow();
793
32970
	instructions[current++].index = arg;
794
795
32970
	do {
796
217413
		arg = va_arg(ap, ssize_t);
797
72471
		grow();
798
72471
		instructions[current++].index = arg;
799
72471
	} while (arg != END_NODE);
800
801
32970
	va_end(ap);
802
32970
	return ret;
803
32970
}
804
805
static void
806
emit(ssize_t i, int level)
807
{
808
140924
	if (level > 1000)
809
		errx(1, "internal error: tree level > 1000");
810
70462
	if (instructions[i].index >= 0) {
811

221011
		while (instructions[i].index != END_NODE &&
812
64288
		    instructions[i].index != i)  {
813
64288
			emit(instructions[i].index, level + 1);
814
64288
			i++;
815
		}
816
42315
	} else if (instructions[i].index != END_NODE)
817
42315
		fputs(instructions[i].u.cstr, stdout);
818
70462
}
819
820
static void
821
emit_macro(int node, ssize_t code)
822
{
823
4116
	putchar('[');
824
1372
	emit(code, 0);
825
1372
	printf("]s%s\n", instructions[node].u.cstr);
826
1372
	nesting--;
827
1372
}
828
829
static void
830
free_tree(void)
831
{
832
	ssize_t i;
833
834
328090
	for (i = 0; i < current; i++)
835
156653
		if (instructions[i].index == ALLOC_STRING)
836
4613
			free(instructions[i].u.astr);
837
4928
	current = 0;
838
4928
}
839
840
static ssize_t
841
numnode(int num)
842
{
843
	const char *p;
844
845
630
	if (num < 10)
846
315
		p = str_table['0' + num];
847
	else if (num < 16)
848
		p = str_table['A' - 10 + num];
849
	else
850
		errx(1, "internal error: break num > 15");
851
315
	return node(cs(" "), cs(p), END_NODE);
852
}
853
854
855
static ssize_t
856
lookup(char * str, size_t len, char type)
857
{
858
	ENTRY	entry, *found;
859
	u_short	num;
860
	u_char	*p;
861
862
	/* The scanner allocated an extra byte already */
863
14616
	if (str[len-1] != type) {
864
3682
		str[len] = type;
865
3682
		str[len+1] = '\0';
866
3682
	}
867
	entry.key = str;
868
7308
	found = hsearch(entry, FIND);
869
7308
	if (found == NULL) {
870
1827
		if (var_count == MAX_VARIABLES)
871
			errx(1, "too many variables");
872
1827
		p = malloc(4);
873
1827
		if (p == NULL)
874
			err(1, NULL);
875
1827
		num = var_count++;
876
1827
		p[0] = 255;
877
1827
		p[1] = ENCODE(num / VAR_BASE + 1);
878
1827
		p[2] = ENCODE(num % VAR_BASE + 1);
879
1827
		p[3] = '\0';
880
881
		entry.data = (char *)p;
882
1827
		entry.key = strdup(str);
883
1827
		if (entry.key == NULL)
884
			err(1, NULL);
885
1827
		found = hsearch(entry, ENTER);
886
1827
		if (found == NULL)
887
			err(1, NULL);
888
	}
889
7308
	return cs(found->data);
890
}
891
892
static ssize_t
893
letter_node(char *str)
894
{
895
	size_t len;
896
897
26726
	len = strlen(str);
898

19488
	if (len == 1 && str[0] != '_')
899
6111
		return cs(str_table[(int)str[0]]);
900
	else
901
7252
		return lookup(str, len, 'L');
902
13363
}
903
904
static ssize_t
905
array_node(char *str)
906
{
907
	size_t len;
908
909
56
	len = strlen(str);
910

56
	if (len == 1 && str[0] != '_')
911
28
		return cs(str_table[(int)str[0] - 'a' + ARRAY_CHAR]);
912
	else
913
		return lookup(str, len, 'A');
914
28
}
915
916
static ssize_t
917
function_node(char *str)
918
{
919
	size_t len;
920
921
574
	len = strlen(str);
922

518
	if (len == 1 && str[0] != '_')
923
231
		return cs(str_table[(int)str[0] - 'a' + FUNC_CHAR]);
924
	else
925
56
		return lookup(str, len, 'F');
926
287
}
927
928
static void
929
add_par(ssize_t n)
930
{
931
238
	prologue = node(cs("S"), n, prologue, END_NODE);
932
119
	epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
933
119
}
934
935
static void
936
add_local(ssize_t n)
937
{
938
714
	prologue = node(cs("0S"), n, prologue, END_NODE);
939
357
	epilogue = node(epilogue, cs("L"), n, cs("s."), END_NODE);
940
357
}
941
942
void
943
yyerror(char *s)
944
{
945
	char	*str, *p;
946
	int	n;
947
948
	if (yyin != NULL && feof(yyin))
949
		n = asprintf(&str, "%s: %s:%d: %s: unexpected EOF",
950
		    __progname, filename, lineno, s);
951
	else if (yytext[0] == '\n')
952
		n = asprintf(&str,
953
		    "%s: %s:%d: %s: newline unexpected",
954
		    __progname, filename, lineno, s);
955
	else if (isspace((unsigned char)yytext[0]) ||
956
	    !isprint((unsigned char)yytext[0]))
957
		n = asprintf(&str,
958
		    "%s: %s:%d: %s: ascii char 0x%02x unexpected",
959
		    __progname, filename, lineno, s, yytext[0] & 0xff);
960
	else
961
		n = asprintf(&str, "%s: %s:%d: %s: %s unexpected",
962
		    __progname, filename, lineno, s, yytext);
963
	if (n == -1)
964
		err(1, NULL);
965
966
	fputs("c[", stdout);
967
	for (p = str; *p != '\0'; p++) {
968
		if (*p == '[' || *p == ']' || *p =='\\')
969
			putchar('\\');
970
		putchar(*p);
971
	}
972
	fputs("]ec\n", stdout);
973
	free(str);
974
}
975
976
void
977
fatal(const char *s)
978
{
979
	errx(1, "%s:%d: %s", filename, lineno, s);
980
}
981
982
static void
983
warning(const char *s)
984
{
985
	warnx("%s:%d: %s", filename, lineno, s);
986
}
987
988
static void
989
init(void)
990
{
991
	int i;
992
993
1393308
	for (i = 0; i < UCHAR_MAX; i++) {
994
692580
		str_table[i][0] = i;
995
692580
		str_table[i][1] = '\0';
996
	}
997
2716
	if (hcreate(1 << 16) == 0)
998
		err(1, NULL);
999
2716
}
1000
1001
1002
static __dead void
1003
usage(void)
1004
{
1005
	fprintf(stderr, "usage: %s [-cl] [-e expression] [file ...]\n",
1006
	    __progname);
1007
	exit(1);
1008
}
1009
1010
static char *
1011
escape(const char *str)
1012
{
1013
	char *ret, *p;
1014
1015
238
	ret = malloc(strlen(str) + 1);
1016
119
	if (ret == NULL)
1017
		err(1, NULL);
1018
1019
	p = ret;
1020
511
	while (*str != '\0') {
1021
		/*
1022
		 * We get _escaped_ strings here. Single backslashes are
1023
		 * already converted to double backslashes
1024
		 */
1025
273
		if (*str == '\\') {
1026
168
			if (*++str == '\\') {
1027


294
				switch (*++str) {
1028
				case 'a':
1029
7
					*p++ = '\a';
1030
7
					break;
1031
				case 'b':
1032
7
					*p++ = '\b';
1033
7
					break;
1034
				case 'f':
1035
7
					*p++ = '\f';
1036
7
					break;
1037
				case 'n':
1038
98
					*p++ = '\n';
1039
98
					break;
1040
				case 'q':
1041
7
					*p++ = '"';
1042
7
					break;
1043
				case 'r':
1044
7
					*p++ = '\r';
1045
7
					break;
1046
				case 't':
1047
7
					*p++ = '\t';
1048
7
					break;
1049
				case '\\':
1050
7
					*p++ = '\\';
1051
7
					break;
1052
				}
1053
147
				str++;
1054
147
			} else {
1055
21
				*p++ = '\\';
1056
21
				*p++ = *str++;
1057
			}
1058
		} else
1059
105
			*p++ = *str++;
1060
	}
1061
119
	*p = '\0';
1062
119
	return ret;
1063
}
1064
1065
/* ARGSUSED */
1066
static void
1067
sigchld(int signo)
1068
{
1069
	pid_t pid;
1070
	int status, save_errno = errno;
1071
1072
	for (;;) {
1073
		pid = waitpid(dc, &status, WCONTINUED | WNOHANG);
1074
		if (pid == -1) {
1075
			if (errno == EINTR)
1076
				continue;
1077
			_exit(0);
1078
		} else if (pid == 0)
1079
			break;
1080
		if (WIFEXITED(status) || WIFSIGNALED(status))
1081
			_exit(0);
1082
		else
1083
			break;
1084
	}
1085
	errno = save_errno;
1086
}
1087
1088
static const char *
1089
dummy_prompt(void)
1090
{
1091
1092
        return ("");
1093
}
1094
1095
int
1096
main(int argc, char *argv[])
1097
{
1098
	int	i, ch;
1099
5432
	int	p[2];
1100
	char	*q;
1101
1102
2716
	if (pledge("stdio rpath wpath cpath flock rpath proc tty", NULL) == -1)
1103
		err(1, "pledge");
1104
1105
2716
	init();
1106
2716
	setvbuf(stdout, NULL, _IOLBF, 0);
1107
1108
2716
	sargv = reallocarray(NULL, argc, sizeof(char *));
1109
2716
	if (sargv == NULL)
1110
		err(1, NULL);
1111
1112
2716
	if ((cmdexpr = strdup("")) == NULL)
1113
		err(1, NULL);
1114
	/* The d debug option is 4.4 BSD bc(1) compatible */
1115
13202
	while ((ch = getopt(argc, argv, "cde:l")) != -1) {
1116

10486
		switch (ch) {
1117
		case 'c':
1118
		case 'd':
1119
126
			do_fork = false;
1120
126
			break;
1121
		case 'e':
1122
7770
			q = cmdexpr;
1123
7770
			if (asprintf(&cmdexpr, "%s%s\n", cmdexpr, optarg) == -1)
1124
				err(1, NULL);
1125
7770
			free(q);
1126
7770
			break;
1127
		case 'l':
1128
2590
			sargv[sargc++] = _PATH_LIBB;
1129
2590
			break;
1130
		default:
1131
			usage();
1132
		}
1133
	}
1134
1135
2716
	argc -= optind;
1136
2716
	argv += optind;
1137
1138

8022
	interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) &&
1139
	    isatty(STDERR_FILENO);
1140
5432
	for (i = 0; i < argc; i++)
1141
		sargv[sargc++] = argv[i];
1142
1143
2716
	if (do_fork) {
1144
2590
		if (pipe(p) == -1)
1145
			err(1, "cannot create pipe");
1146
2590
		dc = fork();
1147
2590
		if (dc == -1)
1148
			err(1, "cannot fork");
1149
2590
		else if (dc != 0) {
1150
			signal(SIGCHLD, sigchld);
1151
			close(STDOUT_FILENO);
1152
			dup(p[1]);
1153
			close(p[0]);
1154
			close(p[1]);
1155
		} else {
1156
2590
			char *dc_argv[] = { "dc", "-x", NULL };
1157
			extern int dc_main(int, char **);
1158
1159
2590
			if (pledge("flock rpath cpath wpath stdio", NULL) == -1)
1160
				err(1, "pledge");
1161
1162
			close(STDIN_FILENO);
1163
			dup(p[0]);
1164
			close(p[0]);
1165
			close(p[1]);
1166
1167
			exit (dc_main(2, dc_argv));
1168
		}
1169
	}
1170
126
	if (interactive) {
1171
		gettty(&ttysaved);
1172
		el = el_init("bc", stdin, stderr, stderr);
1173
		hist = history_init();
1174
		history(hist, &he, H_SETSIZE, 100);
1175
		el_set(el, EL_HIST, history, hist);
1176
		el_set(el, EL_EDITOR, "emacs");
1177
		el_set(el, EL_SIGNAL, 0);
1178
		el_set(el, EL_PROMPT, dummy_prompt);
1179
		el_set(el, EL_ADDFN, "bc_eof", "", bc_eof);
1180
		el_set(el, EL_BIND, "^D", "bc_eof", NULL);
1181
		el_source(el, NULL);
1182
	}
1183
1184
126
	if (pledge("stdio rpath cpath wpath flock rpath tty", NULL) == -1)
1185
		err(1, "pledge");
1186
1187
126
	yywrap();
1188
252
	return yyparse();
1189
126
}