1
2
3
4
5
6
7
8
9
10#define DEBUG_LEXER 0
11#define DEBUG_COMPILE 0
12#define DEBUG_EXEC 0
13
14#define SANITY_CHECKS 1
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204#include "libbb.h"
205#include "common_bufsiz.h"
206
207#if !ENABLE_BC && !ENABLE_FEATURE_DC_BIG
208# include "dc.c"
209#else
210
211#if DEBUG_LEXER
212static uint8_t lex_indent;
213#define dbg_lex(...) \
214 do { \
215 fprintf(stderr, "%*s", lex_indent, ""); \
216 bb_error_msg(__VA_ARGS__); \
217 } while (0)
218#define dbg_lex_enter(...) \
219 do { \
220 dbg_lex(__VA_ARGS__); \
221 lex_indent++; \
222 } while (0)
223#define dbg_lex_done(...) \
224 do { \
225 lex_indent--; \
226 dbg_lex(__VA_ARGS__); \
227 } while (0)
228#else
229# define dbg_lex(...) ((void)0)
230# define dbg_lex_enter(...) ((void)0)
231# define dbg_lex_done(...) ((void)0)
232#endif
233
234#if DEBUG_COMPILE
235# define dbg_compile(...) bb_error_msg(__VA_ARGS__)
236#else
237# define dbg_compile(...) ((void)0)
238#endif
239
240#if DEBUG_EXEC
241# define dbg_exec(...) bb_error_msg(__VA_ARGS__)
242#else
243# define dbg_exec(...) ((void)0)
244#endif
245
246typedef enum BcStatus {
247 BC_STATUS_SUCCESS = 0,
248 BC_STATUS_FAILURE = 1,
249} BcStatus;
250
251#define BC_VEC_INVALID_IDX ((size_t) -1)
252#define BC_VEC_START_CAP (1 << 5)
253
254typedef void (*BcVecFree)(void *) FAST_FUNC;
255
256typedef struct BcVec {
257 char *v;
258 size_t len;
259 size_t cap;
260 size_t size;
261 BcVecFree dtor;
262} BcVec;
263
264typedef signed char BcDig;
265
266typedef struct BcNum {
267 BcDig *restrict num;
268 size_t rdx;
269 size_t len;
270 size_t cap;
271 bool neg;
272} BcNum;
273
274#define BC_NUM_MAX_IBASE 36
275
276#define BC_NUM_DEF_SIZE 16
277#define BC_NUM_PRINT_WIDTH 70
278
279#define BC_NUM_KARATSUBA_LEN 32
280
281typedef enum BcInst {
282#if ENABLE_BC
283 BC_INST_INC_PRE,
284 BC_INST_DEC_PRE,
285 BC_INST_INC_POST,
286 BC_INST_DEC_POST,
287#endif
288 XC_INST_NEG,
289
290 XC_INST_REL_EQ,
291 XC_INST_REL_LE,
292 XC_INST_REL_GE,
293 XC_INST_REL_NE,
294 XC_INST_REL_LT,
295 XC_INST_REL_GT,
296
297 XC_INST_POWER,
298 XC_INST_MULTIPLY,
299 XC_INST_DIVIDE,
300 XC_INST_MODULUS,
301 XC_INST_PLUS,
302 XC_INST_MINUS,
303
304 XC_INST_BOOL_NOT,
305 XC_INST_BOOL_OR,
306 XC_INST_BOOL_AND,
307#if ENABLE_BC
308 BC_INST_ASSIGN_POWER,
309 BC_INST_ASSIGN_MULTIPLY,
310 BC_INST_ASSIGN_DIVIDE,
311 BC_INST_ASSIGN_MODULUS,
312 BC_INST_ASSIGN_PLUS,
313 BC_INST_ASSIGN_MINUS,
314#endif
315 XC_INST_ASSIGN,
316
317 XC_INST_NUM,
318 XC_INST_VAR,
319 XC_INST_ARRAY_ELEM,
320 XC_INST_ARRAY,
321 XC_INST_SCALE_FUNC,
322
323 XC_INST_IBASE,
324 XC_INST_OBASE,
325 XC_INST_SCALE,
326 IF_BC(BC_INST_LAST,)
327 XC_INST_LENGTH,
328 XC_INST_READ,
329 XC_INST_SQRT,
330
331 XC_INST_PRINT,
332 XC_INST_PRINT_POP,
333 XC_INST_STR,
334 XC_INST_PRINT_STR,
335
336#if ENABLE_BC
337 BC_INST_HALT,
338 BC_INST_JUMP,
339 BC_INST_JUMP_ZERO,
340
341 BC_INST_CALL,
342 BC_INST_RET0,
343#endif
344 XC_INST_RET,
345
346 XC_INST_POP,
347#if ENABLE_DC
348 DC_INST_POP_EXEC,
349
350 DC_INST_MODEXP,
351 DC_INST_DIVMOD,
352
353 DC_INST_EXECUTE,
354 DC_INST_EXEC_COND,
355
356 DC_INST_ASCIIFY,
357 DC_INST_PRINT_STREAM,
358
359 DC_INST_PRINT_STACK,
360 DC_INST_CLEAR_STACK,
361 DC_INST_STACK_LEN,
362 DC_INST_DUPLICATE,
363 DC_INST_SWAP,
364
365 DC_INST_LOAD,
366 DC_INST_PUSH_VAR,
367 DC_INST_PUSH_TO_VAR,
368
369 DC_INST_QUIT,
370 DC_INST_NQUIT,
371
372 DC_INST_INVALID = -1,
373#endif
374} BcInst;
375
376typedef struct BcId {
377 char *name;
378 size_t idx;
379} BcId;
380
381typedef struct BcFunc {
382 BcVec code;
383 IF_BC(BcVec labels;)
384 IF_BC(BcVec autos;)
385 IF_BC(BcVec strs;)
386 IF_BC(BcVec consts;)
387 IF_BC(size_t nparams;)
388 IF_BC(bool voidfunc;)
389} BcFunc;
390
391typedef enum BcResultType {
392 XC_RESULT_TEMP,
393 IF_BC(BC_RESULT_VOID,)
394
395 XC_RESULT_VAR,
396 XC_RESULT_ARRAY_ELEM,
397 XC_RESULT_ARRAY,
398
399 XC_RESULT_STR,
400
401
402 XC_RESULT_IBASE,
403 XC_RESULT_OBASE,
404 XC_RESULT_SCALE,
405 IF_BC(BC_RESULT_LAST,)
406 XC_RESULT_CONSTANT,
407 IF_BC(BC_RESULT_ONE,)
408} BcResultType;
409
410typedef union BcResultData {
411 BcNum n;
412 BcVec v;
413 BcId id;
414} BcResultData;
415
416typedef struct BcResult {
417 BcResultType t;
418 BcResultData d;
419} BcResult;
420
421typedef struct BcInstPtr {
422 size_t func;
423 size_t inst_idx;
424} BcInstPtr;
425
426typedef enum BcType {
427 BC_TYPE_VAR,
428 BC_TYPE_ARRAY,
429 BC_TYPE_REF,
430} BcType;
431
432typedef enum BcLexType {
433 XC_LEX_EOF,
434 XC_LEX_INVALID,
435
436 XC_LEX_NLINE,
437 XC_LEX_WHITESPACE,
438 XC_LEX_STR,
439 XC_LEX_NAME,
440 XC_LEX_NUMBER,
441
442 XC_LEX_1st_op,
443 XC_LEX_NEG = XC_LEX_1st_op,
444
445 XC_LEX_OP_REL_EQ,
446 XC_LEX_OP_REL_LE,
447 XC_LEX_OP_REL_GE,
448 XC_LEX_OP_REL_NE,
449 XC_LEX_OP_REL_LT,
450 XC_LEX_OP_REL_GT,
451
452 XC_LEX_OP_POWER,
453 XC_LEX_OP_MULTIPLY,
454 XC_LEX_OP_DIVIDE,
455 XC_LEX_OP_MODULUS,
456 XC_LEX_OP_PLUS,
457 XC_LEX_OP_MINUS,
458 XC_LEX_OP_last = XC_LEX_OP_MINUS,
459#if ENABLE_BC
460 BC_LEX_OP_BOOL_NOT,
461 BC_LEX_OP_BOOL_OR,
462 BC_LEX_OP_BOOL_AND,
463
464 BC_LEX_OP_ASSIGN_POWER,
465 BC_LEX_OP_ASSIGN_MULTIPLY,
466 BC_LEX_OP_ASSIGN_DIVIDE,
467 BC_LEX_OP_ASSIGN_MODULUS,
468 BC_LEX_OP_ASSIGN_PLUS,
469 BC_LEX_OP_ASSIGN_MINUS,
470
471 BC_LEX_OP_ASSIGN,
472
473 BC_LEX_OP_INC,
474 BC_LEX_OP_DEC,
475
476 BC_LEX_LPAREN,
477 BC_LEX_RPAREN,
478
479 BC_LEX_LBRACKET,
480 BC_LEX_COMMA,
481 BC_LEX_RBRACKET,
482
483 BC_LEX_LBRACE,
484 BC_LEX_SCOLON,
485 BC_LEX_RBRACE,
486
487 BC_LEX_KEY_1st_keyword,
488 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
489 BC_LEX_KEY_BREAK,
490 BC_LEX_KEY_CONTINUE,
491 BC_LEX_KEY_DEFINE,
492 BC_LEX_KEY_ELSE,
493 BC_LEX_KEY_FOR,
494 BC_LEX_KEY_HALT,
495
496 BC_LEX_KEY_IBASE,
497 BC_LEX_KEY_OBASE,
498 BC_LEX_KEY_IF,
499 BC_LEX_KEY_LAST,
500 BC_LEX_KEY_LENGTH,
501 BC_LEX_KEY_LIMITS,
502 BC_LEX_KEY_PRINT,
503 BC_LEX_KEY_QUIT,
504 BC_LEX_KEY_READ,
505 BC_LEX_KEY_RETURN,
506 BC_LEX_KEY_SCALE,
507 BC_LEX_KEY_SQRT,
508 BC_LEX_KEY_WHILE,
509#endif
510
511#if ENABLE_DC
512 DC_LEX_OP_BOOL_NOT = XC_LEX_OP_last + 1,
513 DC_LEX_OP_ASSIGN,
514
515 DC_LEX_LPAREN,
516 DC_LEX_SCOLON,
517 DC_LEX_READ,
518 DC_LEX_IBASE,
519 DC_LEX_SCALE,
520 DC_LEX_OBASE,
521 DC_LEX_LENGTH,
522 DC_LEX_PRINT,
523 DC_LEX_QUIT,
524 DC_LEX_SQRT,
525 DC_LEX_LBRACE,
526
527 DC_LEX_EQ_NO_REG,
528 DC_LEX_OP_MODEXP,
529 DC_LEX_OP_DIVMOD,
530
531 DC_LEX_COLON,
532 DC_LEX_ELSE,
533 DC_LEX_EXECUTE,
534 DC_LEX_PRINT_STACK,
535 DC_LEX_CLEAR_STACK,
536 DC_LEX_STACK_LEVEL,
537 DC_LEX_DUPLICATE,
538 DC_LEX_SWAP,
539 DC_LEX_POP,
540
541 DC_LEX_ASCIIFY,
542 DC_LEX_PRINT_STREAM,
543
544
545 DC_LEX_STORE_IBASE,
546 DC_LEX_STORE_OBASE,
547 DC_LEX_STORE_SCALE,
548 DC_LEX_LOAD,
549 DC_LEX_LOAD_POP,
550 DC_LEX_STORE_PUSH,
551 DC_LEX_PRINT_POP,
552 DC_LEX_NQUIT,
553 DC_LEX_SCALE_FACTOR,
554#endif
555} BcLexType;
556
557#if ENABLE_BC
558struct BcLexKeyword {
559 char name8[8];
560};
561#define LEX_KW_ENTRY(a, b) \
562 { .name8 = a }
563static const struct BcLexKeyword bc_lex_kws[20] ALIGN8 = {
564 LEX_KW_ENTRY("auto" , 1),
565 LEX_KW_ENTRY("break" , 1),
566 LEX_KW_ENTRY("continue", 0),
567 LEX_KW_ENTRY("define" , 1),
568 LEX_KW_ENTRY("else" , 0),
569 LEX_KW_ENTRY("for" , 1),
570 LEX_KW_ENTRY("halt" , 0),
571 LEX_KW_ENTRY("ibase" , 1),
572 LEX_KW_ENTRY("obase" , 1),
573 LEX_KW_ENTRY("if" , 1),
574 LEX_KW_ENTRY("last" , 0),
575 LEX_KW_ENTRY("length" , 1),
576 LEX_KW_ENTRY("limits" , 0),
577 LEX_KW_ENTRY("print" , 0),
578 LEX_KW_ENTRY("quit" , 1),
579 LEX_KW_ENTRY("read" , 0),
580 LEX_KW_ENTRY("return" , 1),
581 LEX_KW_ENTRY("scale" , 1),
582 LEX_KW_ENTRY("sqrt" , 1),
583 LEX_KW_ENTRY("while" , 1),
584};
585#undef LEX_KW_ENTRY
586#define STRING_else (bc_lex_kws[4].name8)
587#define STRING_for (bc_lex_kws[5].name8)
588#define STRING_if (bc_lex_kws[9].name8)
589#define STRING_while (bc_lex_kws[19].name8)
590enum {
591 POSIX_KWORD_MASK = 0
592 | (1 << 0)
593 | (1 << 1)
594 | (0 << 2)
595 | (1 << 3)
596 | (0 << 4)
597 | (1 << 5)
598 | (0 << 6)
599 | (1 << 7)
600 | (1 << 8)
601 | (1 << 9)
602 | (0 << 10)
603 | (1 << 11)
604 | (0 << 12)
605 | (0 << 13)
606 | (1 << 14)
607 | (0 << 15)
608 | (1 << 16)
609 | (1 << 17)
610 | (1 << 18)
611 | (1 << 19)
612};
613#define keyword_is_POSIX(i) ((1 << (i)) & POSIX_KWORD_MASK)
614
615
616
617
618
619
620
621enum {
622#define EXBITS(a,b,c,d,e,f,g,h) \
623 ((uint64_t)((a << 0)+(b << 1)+(c << 2)+(d << 3)+(e << 4)+(f << 5)+(g << 6)+(h << 7)))
624 BC_PARSE_EXPRS_BITS = 0
625 + (EXBITS(0,0,0,0,0,1,1,1) << (0*8))
626 + (EXBITS(1,1,1,1,1,1,1,1) << (1*8))
627 + (EXBITS(1,1,1,1,1,1,1,1) << (2*8))
628 + (EXBITS(1,1,1,1,1,1,1,1) << (3*8))
629 + (EXBITS(1,1,0,0,0,0,0,0) << (4*8))
630 + (EXBITS(0,0,0,0,0,0,0,1) << (5*8))
631 + (EXBITS(1,0,1,1,0,0,0,1) << (6*8))
632 + (EXBITS(0,1,1,0,0,0,0,0) << (7*8))
633#undef EXBITS
634};
635static ALWAYS_INLINE long lex_allowed_in_bc_expr(unsigned i)
636{
637#if ULONG_MAX > 0xffffffff
638
639 return BC_PARSE_EXPRS_BITS & (1UL << i);
640#else
641
642 unsigned long m = (uint32_t)BC_PARSE_EXPRS_BITS;
643 if (i >= 32) {
644 m = (uint32_t)(BC_PARSE_EXPRS_BITS >> 32);
645 i &= 31;
646 }
647 return m & (1UL << i);
648#endif
649}
650
651
652
653static const uint8_t bc_ops_prec_and_assoc[] ALIGN1 = {
654#define OP(p,l) ((int)(l) * 0x10 + (p))
655 OP(1, false),
656 OP(6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ),
657 OP(2, false),
658 OP(3, true ), OP( 3, true ), OP( 3, true ),
659 OP(4, true ), OP( 4, true ),
660 OP(1, false),
661 OP(7, true ), OP( 7, true ),
662 OP(5, false), OP( 5, false ), OP( 5, false ), OP( 5, false ), OP( 5, false ),
663 OP(5, false), OP( 5, false ),
664 OP(0, false), OP( 0, false ),
665#undef OP
666};
667#define bc_operation_PREC(i) (bc_ops_prec_and_assoc[i] & 0x0f)
668#define bc_operation_LEFT(i) (bc_ops_prec_and_assoc[i] & 0x10)
669#endif
670
671#if ENABLE_DC
672static const
673uint8_t
674dc_char_to_LEX[] ALIGN1 = {
675
676 XC_LEX_OP_MODULUS, XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_LPAREN,
677
678 XC_LEX_INVALID, XC_LEX_OP_MULTIPLY, XC_LEX_OP_PLUS, XC_LEX_INVALID,
679
680 XC_LEX_OP_MINUS, XC_LEX_INVALID, XC_LEX_OP_DIVIDE,
681
682 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
683 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
684 XC_LEX_INVALID, XC_LEX_INVALID,
685
686 DC_LEX_COLON, DC_LEX_SCOLON, XC_LEX_OP_REL_GT, XC_LEX_OP_REL_EQ,
687 XC_LEX_OP_REL_LT, DC_LEX_READ, XC_LEX_INVALID,
688
689 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
690 XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_EQ_NO_REG, XC_LEX_INVALID,
691
692 DC_LEX_IBASE, XC_LEX_INVALID, DC_LEX_SCALE, DC_LEX_LOAD_POP,
693 XC_LEX_INVALID, DC_LEX_OP_BOOL_NOT, DC_LEX_OBASE, DC_LEX_PRINT_STREAM,
694
695 DC_LEX_NQUIT, DC_LEX_POP, DC_LEX_STORE_PUSH, XC_LEX_INVALID,
696 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_SCALE_FACTOR,
697
698 XC_LEX_INVALID, DC_LEX_LENGTH,
699
700 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
701
702 XC_LEX_OP_POWER, XC_LEX_NEG, XC_LEX_INVALID,
703
704 DC_LEX_ASCIIFY, XC_LEX_INVALID, DC_LEX_CLEAR_STACK, DC_LEX_DUPLICATE,
705 DC_LEX_ELSE, DC_LEX_PRINT_STACK, XC_LEX_INVALID, XC_LEX_INVALID,
706
707 DC_LEX_STORE_IBASE, XC_LEX_INVALID, DC_LEX_STORE_SCALE, DC_LEX_LOAD,
708 XC_LEX_INVALID, DC_LEX_PRINT_POP, DC_LEX_STORE_OBASE, DC_LEX_PRINT,
709
710 DC_LEX_QUIT, DC_LEX_SWAP, DC_LEX_OP_ASSIGN, XC_LEX_INVALID,
711 XC_LEX_INVALID, DC_LEX_SQRT, XC_LEX_INVALID, DC_LEX_EXECUTE,
712
713 XC_LEX_INVALID, DC_LEX_STACK_LEVEL,
714
715 DC_LEX_LBRACE, DC_LEX_OP_MODEXP, XC_LEX_INVALID, DC_LEX_OP_DIVMOD,
716};
717static const
718int8_t
719dc_LEX_to_INST[] ALIGN1 = {
720 XC_INST_POWER, XC_INST_MULTIPLY,
721 XC_INST_DIVIDE, XC_INST_MODULUS,
722 XC_INST_PLUS, XC_INST_MINUS,
723 XC_INST_BOOL_NOT,
724 DC_INST_INVALID,
725 XC_INST_REL_GT,
726 DC_INST_INVALID,
727 DC_INST_INVALID,
728 XC_INST_IBASE,
729 XC_INST_SCALE,
730 XC_INST_OBASE,
731 XC_INST_LENGTH,
732 XC_INST_PRINT,
733 DC_INST_QUIT,
734 XC_INST_SQRT,
735 XC_INST_REL_GE,
736 XC_INST_REL_EQ,
737 DC_INST_MODEXP, DC_INST_DIVMOD,
738 DC_INST_INVALID, DC_INST_INVALID,
739 DC_INST_EXECUTE,
740 DC_INST_PRINT_STACK, DC_INST_CLEAR_STACK,
741 DC_INST_STACK_LEN, DC_INST_DUPLICATE,
742 DC_INST_SWAP, XC_INST_POP,
743 DC_INST_ASCIIFY, DC_INST_PRINT_STREAM,
744 DC_INST_INVALID, DC_INST_INVALID,
745 DC_INST_INVALID, DC_INST_INVALID,
746 DC_INST_INVALID, DC_INST_INVALID,
747 XC_INST_PRINT, DC_INST_NQUIT,
748 XC_INST_SCALE_FUNC,
749
750
751
752};
753#endif
754
755typedef struct BcParse {
756 smallint lex;
757 smallint lex_last;
758 size_t lex_line;
759 const char *lex_inbuf;
760 const char *lex_next_at;
761 const char *lex_filename;
762 FILE *lex_input_fp;
763 BcVec lex_strnumbuf;
764
765 BcFunc *func;
766 size_t fidx;
767 IF_BC(size_t in_funcdef;)
768 IF_BC(BcVec exits;)
769 IF_BC(BcVec conds;)
770 IF_BC(BcVec ops;)
771} BcParse;
772
773typedef struct BcProgram {
774 size_t len;
775 size_t nchars;
776
777 size_t scale;
778 size_t ib_t;
779 size_t ob_t;
780
781 BcVec results;
782 BcVec exestack;
783
784 BcVec fns;
785 IF_BC(BcVec fn_map;)
786
787 BcVec vars;
788 BcVec var_map;
789
790 BcVec arrs;
791 BcVec arr_map;
792
793 IF_DC(BcVec strs;)
794 IF_DC(BcVec consts;)
795
796 BcNum zero;
797 IF_BC(BcNum one;)
798 IF_BC(BcNum last;)
799} BcProgram;
800
801struct globals {
802 BcParse prs;
803
804
805
806 size_t err_line;
807
808 BcVec input_buffer;
809
810 IF_FEATURE_BC_INTERACTIVE(smallint ttyin;)
811 IF_FEATURE_CLEAN_UP(smallint exiting;)
812
813 BcProgram prog;
814
815 BcVec files;
816
817 char *env_args;
818
819#if ENABLE_FEATURE_EDITING
820 line_input_t *line_input_state;
821#endif
822} FIX_ALIASING;
823#define G (*ptr_to_globals)
824#define INIT_G() do { \
825 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
826} while (0)
827#define FREE_G() do { \
828 FREE_PTR_TO_GLOBALS(); \
829} while (0)
830#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
831#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
832#define G_exreg (ENABLE_DC && (option_mask32 & DC_FLAG_X))
833#if ENABLE_FEATURE_BC_INTERACTIVE
834# define G_interrupt bb_got_signal
835# define G_ttyin G.ttyin
836#else
837# define G_interrupt 0
838# define G_ttyin 0
839#endif
840#if ENABLE_FEATURE_CLEAN_UP
841# define G_exiting G.exiting
842#else
843# define G_exiting 0
844#endif
845#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
846#define IS_DC (ENABLE_DC && (!ENABLE_BC || applet_name[0] != 'b'))
847
848#if ENABLE_BC
849# define BC_PARSE_REL (1 << 0)
850# define BC_PARSE_PRINT (1 << 1)
851# define BC_PARSE_ARRAY (1 << 2)
852# define BC_PARSE_NOCALL (1 << 3)
853#endif
854
855#define BC_PROG_MAIN 0
856#define BC_PROG_READ 1
857#if ENABLE_DC
858#define BC_PROG_REQ_FUNCS 2
859#endif
860
861#define BC_FLAG_W (1 << 0)
862#define BC_FLAG_V (1 << 1)
863#define BC_FLAG_S (1 << 2)
864#define BC_FLAG_Q (1 << 3)
865#define BC_FLAG_L (1 << 4)
866#define BC_FLAG_I ((1 << 5) * ENABLE_DC)
867#define DC_FLAG_X ((1 << 6) * ENABLE_DC)
868
869#define BC_MAX_OBASE ((unsigned) 999)
870#define BC_MAX_DIM ((unsigned) INT_MAX)
871#define BC_MAX_SCALE ((unsigned) UINT_MAX)
872#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
873#define BC_MAX_NUM BC_MAX_STRING
874
875
876
877#define BC_MAX_EXP_STR "999999999"
878#define BC_MAX_VARS_STR "999999999"
879
880#define BC_MAX_OBASE_STR "999"
881
882#if INT_MAX == 2147483647
883# define BC_MAX_DIM_STR "2147483647"
884#elif INT_MAX == 9223372036854775807
885# define BC_MAX_DIM_STR "9223372036854775807"
886#else
887# error Strange INT_MAX
888#endif
889
890#if UINT_MAX == 4294967295U
891# define BC_MAX_SCALE_STR "4294967295"
892# define BC_MAX_STRING_STR "4294967294"
893#elif UINT_MAX == 18446744073709551615U
894# define BC_MAX_SCALE_STR "18446744073709551615"
895# define BC_MAX_STRING_STR "18446744073709551614"
896#else
897# error Strange UINT_MAX
898#endif
899#define BC_MAX_NUM_STR BC_MAX_STRING_STR
900
901
902
903
904
905
906
907
908
909
910
911
912#if ENABLE_FEATURE_BC_INTERACTIVE || ENABLE_FEATURE_CLEAN_UP
913# define ERRORS_ARE_FATAL 0
914# define ERRORFUNC
915# define IF_ERROR_RETURN_POSSIBLE(a) a
916# define BC_STATUS BcStatus
917# define RETURN_STATUS(v) return (v)
918# define COMMA_SUCCESS
919#else
920# define ERRORS_ARE_FATAL 1
921# define ERRORFUNC NORETURN
922# define IF_ERROR_RETURN_POSSIBLE(a)
923# define BC_STATUS void
924# define RETURN_STATUS(v) do { ((void)(v)); return; } while (0)
925# define COMMA_SUCCESS ,BC_STATUS_SUCCESS
926#endif
927
928
929
930
931
932#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
933#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
934
935static void fflush_and_check(void)
936{
937 fflush_all();
938 if (ferror(stdout) || ferror(stderr))
939 bb_simple_perror_msg_and_die("output error");
940}
941
942#if ENABLE_FEATURE_CLEAN_UP
943#define QUIT_OR_RETURN_TO_MAIN \
944do { \
945 IF_FEATURE_BC_INTERACTIVE(G_ttyin = 0;) \
946 G_exiting = 1; \
947 return BC_STATUS_FAILURE; \
948} while (0)
949#else
950static void quit(void) NORETURN;
951static void quit(void)
952{
953 if (ferror(stdin))
954 bb_simple_perror_msg_and_die("input error");
955 fflush_and_check();
956 dbg_exec("quit(): exiting with exitcode SUCCESS");
957 exit(0);
958}
959#define QUIT_OR_RETURN_TO_MAIN quit()
960#endif
961
962static void bc_verror_msg(const char *fmt, va_list p)
963{
964 const char *sv = sv;
965 if (G.prs.lex_filename) {
966 sv = applet_name;
967 applet_name = xasprintf("%s: %s:%lu", applet_name,
968 G.prs.lex_filename, (unsigned long)G.err_line
969 );
970 }
971 bb_verror_msg(fmt, p, NULL);
972 if (G.prs.lex_filename) {
973 free((char*)applet_name);
974 applet_name = sv;
975 }
976}
977
978static NOINLINE ERRORFUNC int bc_error_fmt(const char *fmt, ...)
979{
980 va_list p;
981
982 va_start(p, fmt);
983 bc_verror_msg(fmt, p);
984 va_end(p);
985
986 if (ENABLE_FEATURE_CLEAN_UP || G_ttyin)
987 IF_ERROR_RETURN_POSSIBLE(return BC_STATUS_FAILURE);
988 exit(1);
989}
990
991#if ENABLE_BC
992static NOINLINE BC_STATUS zbc_posix_error_fmt(const char *fmt, ...)
993{
994 va_list p;
995
996
997 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
998 RETURN_STATUS(BC_STATUS_SUCCESS);
999
1000 va_start(p, fmt);
1001 bc_verror_msg(fmt, p);
1002 va_end(p);
1003
1004
1005 if (!(option_mask32 & BC_FLAG_S))
1006 RETURN_STATUS(BC_STATUS_SUCCESS);
1007
1008 if (ENABLE_FEATURE_CLEAN_UP || G_ttyin)
1009 RETURN_STATUS(BC_STATUS_FAILURE);
1010 exit(1);
1011}
1012#define zbc_posix_error_fmt(...) (zbc_posix_error_fmt(__VA_ARGS__) COMMA_SUCCESS)
1013#endif
1014
1015
1016
1017
1018
1019
1020static ERRORFUNC int bc_error(const char *msg)
1021{
1022 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("%s", msg);
1023}
1024static ERRORFUNC int bc_error_at(const char *msg)
1025{
1026 const char *err_at = G.prs.lex_next_at;
1027 if (err_at) {
1028 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt(
1029 "%s at '%.*s'",
1030 msg,
1031 (int)(strchrnul(err_at, '\n') - err_at),
1032 err_at
1033 );
1034 }
1035 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("%s", msg);
1036}
1037static ERRORFUNC int bc_error_bad_character(char c)
1038{
1039 if (!c)
1040 IF_ERROR_RETURN_POSSIBLE(return) bc_error("NUL character");
1041 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("bad character '%c'", c);
1042}
1043#if ENABLE_BC
1044static ERRORFUNC int bc_error_bad_function_definition(void)
1045{
1046 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad function definition");
1047}
1048#endif
1049static ERRORFUNC int bc_error_bad_expression(void)
1050{
1051 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad expression");
1052}
1053static ERRORFUNC int bc_error_bad_assignment(void)
1054{
1055 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at(
1056 "bad assignment: left side must be variable or array element"
1057 );
1058}
1059static ERRORFUNC int bc_error_bad_token(void)
1060{
1061 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad token");
1062}
1063static ERRORFUNC int bc_error_stack_has_too_few_elements(void)
1064{
1065 IF_ERROR_RETURN_POSSIBLE(return) bc_error("stack has too few elements");
1066}
1067static ERRORFUNC int bc_error_variable_is_wrong_type(void)
1068{
1069 IF_ERROR_RETURN_POSSIBLE(return) bc_error("variable is wrong type");
1070}
1071#if ENABLE_BC
1072static BC_STATUS zbc_POSIX_requires(const char *msg)
1073{
1074 RETURN_STATUS(zbc_posix_error_fmt("POSIX requires %s", msg));
1075}
1076#define zbc_POSIX_requires(...) (zbc_POSIX_requires(__VA_ARGS__) COMMA_SUCCESS)
1077static BC_STATUS zbc_POSIX_does_not_allow(const char *msg)
1078{
1079 RETURN_STATUS(zbc_posix_error_fmt("%s%s", "POSIX does not allow ", msg));
1080}
1081#define zbc_POSIX_does_not_allow(...) (zbc_POSIX_does_not_allow(__VA_ARGS__) COMMA_SUCCESS)
1082static BC_STATUS zbc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1083{
1084 RETURN_STATUS(zbc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; this is bad:", msg));
1085}
1086#define zbc_POSIX_does_not_allow_bool_ops_this_is_bad(...) (zbc_POSIX_does_not_allow_bool_ops_this_is_bad(__VA_ARGS__) COMMA_SUCCESS)
1087static BC_STATUS zbc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1088{
1089 RETURN_STATUS(zbc_posix_error_fmt("%san empty %s expression in 'for()'", "POSIX does not allow ", msg));
1090}
1091#define zbc_POSIX_does_not_allow_empty_X_expression_in_for(...) (zbc_POSIX_does_not_allow_empty_X_expression_in_for(__VA_ARGS__) COMMA_SUCCESS)
1092#endif
1093
1094static void bc_vec_grow(BcVec *v, size_t n)
1095{
1096 size_t cap = v->cap * 2;
1097 while (cap < v->len + n) cap *= 2;
1098 v->v = xrealloc(v->v, v->size * cap);
1099 v->cap = cap;
1100}
1101
1102static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1103{
1104 v->size = esize;
1105 v->cap = BC_VEC_START_CAP;
1106 v->len = 0;
1107 v->dtor = dtor;
1108 v->v = xmalloc(esize * BC_VEC_START_CAP);
1109}
1110
1111static void bc_char_vec_init(BcVec *v)
1112{
1113 bc_vec_init(v, sizeof(char), NULL);
1114}
1115
1116static void bc_vec_expand(BcVec *v, size_t req)
1117{
1118 if (v->cap < req) {
1119 v->v = xrealloc(v->v, v->size * req);
1120 v->cap = req;
1121 }
1122}
1123
1124static void bc_vec_pop(BcVec *v)
1125{
1126 v->len--;
1127 if (v->dtor)
1128 v->dtor(v->v + (v->size * v->len));
1129}
1130
1131static void bc_vec_npop(BcVec *v, size_t n)
1132{
1133 if (!v->dtor)
1134 v->len -= n;
1135 else {
1136 size_t len = v->len - n;
1137 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1138 }
1139}
1140
1141static void bc_vec_pop_all(BcVec *v)
1142{
1143 bc_vec_npop(v, v->len);
1144}
1145
1146static size_t bc_vec_npush(BcVec *v, size_t n, const void *data)
1147{
1148 size_t len = v->len;
1149 if (len + n > v->cap) bc_vec_grow(v, n);
1150 memmove(v->v + (v->size * len), data, v->size * n);
1151 v->len = len + n;
1152 return len;
1153}
1154
1155static size_t bc_vec_push(BcVec *v, const void *data)
1156{
1157 return bc_vec_npush(v, 1, data);
1158
1159
1160
1161
1162
1163}
1164
1165
1166
1167static size_t bc_result_pop_and_push(const void *data)
1168{
1169 BcVec *v = &G.prog.results;
1170 char *last;
1171 size_t len = v->len - 1;
1172
1173 last = v->v + (v->size * len);
1174 if (v->dtor)
1175 v->dtor(last);
1176 memmove(last, data, v->size);
1177 return len;
1178}
1179
1180static size_t bc_vec_pushByte(BcVec *v, char data)
1181{
1182 return bc_vec_push(v, &data);
1183}
1184
1185static size_t bc_vec_pushZeroByte(BcVec *v)
1186{
1187
1188
1189 return bc_vec_push(v, &const_int_0);
1190}
1191
1192static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1193{
1194 if (idx == v->len)
1195 bc_vec_push(v, data);
1196 else {
1197 char *ptr;
1198
1199 if (v->len == v->cap) bc_vec_grow(v, 1);
1200
1201 ptr = v->v + v->size * idx;
1202
1203 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1204 memmove(ptr, data, v->size);
1205 }
1206}
1207
1208static void bc_vec_string(BcVec *v, size_t len, const char *str)
1209{
1210 bc_vec_pop_all(v);
1211 bc_vec_expand(v, len + 1);
1212 memcpy(v->v, str, len);
1213 v->len = len;
1214
1215 bc_vec_pushZeroByte(v);
1216}
1217
1218static void *bc_vec_item(const BcVec *v, size_t idx)
1219{
1220 return v->v + v->size * idx;
1221}
1222
1223static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1224{
1225 return v->v + v->size * (v->len - idx - 1);
1226}
1227
1228static void *bc_vec_top(const BcVec *v)
1229{
1230 return v->v + v->size * (v->len - 1);
1231}
1232
1233static FAST_FUNC void bc_vec_free(void *vec)
1234{
1235 BcVec *v = (BcVec *) vec;
1236 bc_vec_pop_all(v);
1237 free(v->v);
1238}
1239
1240static BcFunc* xc_program_func(size_t idx)
1241{
1242 return bc_vec_item(&G.prog.fns, idx);
1243}
1244
1245#define xc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v))
1246
1247#if ENABLE_BC
1248static BcFunc* bc_program_current_func(void)
1249{
1250 BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
1251 BcFunc *func = xc_program_func(ip->func);
1252 return func;
1253}
1254#endif
1255
1256static char** xc_program_str(size_t idx)
1257{
1258#if ENABLE_BC
1259 if (IS_BC) {
1260 BcFunc *func = bc_program_current_func();
1261 return bc_vec_item(&func->strs, idx);
1262 }
1263#endif
1264 IF_DC(return bc_vec_item(&G.prog.strs, idx);)
1265}
1266
1267static char** xc_program_const(size_t idx)
1268{
1269#if ENABLE_BC
1270 if (IS_BC) {
1271 BcFunc *func = bc_program_current_func();
1272 return bc_vec_item(&func->consts, idx);
1273 }
1274#endif
1275 IF_DC(return bc_vec_item(&G.prog.consts, idx);)
1276}
1277
1278static int bc_id_cmp(const void *e1, const void *e2)
1279{
1280 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
1281}
1282
1283static FAST_FUNC void bc_id_free(void *id)
1284{
1285 free(((BcId *) id)->name);
1286}
1287
1288static size_t bc_map_find_ge(const BcVec *v, const void *ptr)
1289{
1290 size_t low = 0, high = v->len;
1291
1292 while (low < high) {
1293 size_t mid = (low + high) / 2;
1294 BcId *id = bc_vec_item(v, mid);
1295 int result = bc_id_cmp(ptr, id);
1296
1297 if (result == 0)
1298 return mid;
1299 if (result < 0)
1300 high = mid;
1301 else
1302 low = mid + 1;
1303 }
1304
1305 return low;
1306}
1307
1308static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1309{
1310 size_t n = *i = bc_map_find_ge(v, ptr);
1311
1312 if (n == v->len)
1313 bc_vec_push(v, ptr);
1314 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1315 return 0;
1316 else
1317 bc_vec_pushAt(v, ptr, n);
1318 return 1;
1319}
1320
1321static size_t bc_map_find_exact(const BcVec *v, const void *ptr)
1322{
1323 size_t i = bc_map_find_ge(v, ptr);
1324 if (i >= v->len) return BC_VEC_INVALID_IDX;
1325 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1326}
1327
1328static void bc_num_setToZero(BcNum *n, size_t scale)
1329{
1330 n->len = 0;
1331 n->neg = false;
1332 n->rdx = scale;
1333}
1334
1335static void bc_num_zero(BcNum *n)
1336{
1337 bc_num_setToZero(n, 0);
1338}
1339
1340static void bc_num_one(BcNum *n)
1341{
1342 bc_num_setToZero(n, 0);
1343 n->len = 1;
1344 n->num[0] = 1;
1345}
1346
1347
1348static void bc_num_init(BcNum *n, size_t req)
1349{
1350 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1351
1352 n->num = xmalloc(req);
1353 n->cap = req;
1354 n->rdx = 0;
1355 n->len = 0;
1356 n->neg = false;
1357}
1358
1359static void bc_num_init_DEF_SIZE(BcNum *n)
1360{
1361 bc_num_init(n, BC_NUM_DEF_SIZE);
1362}
1363
1364static void bc_num_expand(BcNum *n, size_t req)
1365{
1366 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1367 if (req > n->cap) {
1368 n->num = xrealloc(n->num, req);
1369 n->cap = req;
1370 }
1371}
1372
1373static FAST_FUNC void bc_num_free(void *num)
1374{
1375 free(((BcNum *) num)->num);
1376}
1377
1378static void bc_num_copy(BcNum *d, BcNum *s)
1379{
1380 if (d != s) {
1381 bc_num_expand(d, s->cap);
1382 d->len = s->len;
1383 d->neg = s->neg;
1384 d->rdx = s->rdx;
1385 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
1386 }
1387}
1388
1389static void bc_num_init_and_copy(BcNum *d, BcNum *s)
1390{
1391 bc_num_init(d, s->len);
1392 bc_num_copy(d, s);
1393}
1394
1395static BC_STATUS zbc_num_ulong_abs(BcNum *n, unsigned long *result_p)
1396{
1397 size_t i;
1398 unsigned long result;
1399
1400 result = 0;
1401 i = n->len;
1402 while (i > n->rdx) {
1403 unsigned long prev = result;
1404 result = result * 10 + n->num[--i];
1405
1406
1407
1408
1409 if ((result / 8) < prev)
1410 RETURN_STATUS(bc_error("overflow"));
1411 }
1412 *result_p = result;
1413
1414 RETURN_STATUS(BC_STATUS_SUCCESS);
1415}
1416#define zbc_num_ulong_abs(...) (zbc_num_ulong_abs(__VA_ARGS__) COMMA_SUCCESS)
1417
1418static BC_STATUS zbc_num_ulong(BcNum *n, unsigned long *result_p)
1419{
1420 if (n->neg) RETURN_STATUS(bc_error("negative number"));
1421
1422 RETURN_STATUS(zbc_num_ulong_abs(n, result_p));
1423}
1424#define zbc_num_ulong(...) (zbc_num_ulong(__VA_ARGS__) COMMA_SUCCESS)
1425
1426#if ULONG_MAX == 0xffffffffUL
1427# define ULONG_NUM_BUFSIZE (10 > BC_NUM_DEF_SIZE ? 10 : BC_NUM_DEF_SIZE)
1428#elif ULONG_MAX == 0xffffffffffffffffULL
1429# define ULONG_NUM_BUFSIZE (20 > BC_NUM_DEF_SIZE ? 20 : BC_NUM_DEF_SIZE)
1430#endif
1431
1432
1433
1434static void bc_num_ulong2num(BcNum *n, unsigned long val)
1435{
1436 BcDig *ptr;
1437
1438 bc_num_zero(n);
1439
1440 if (val == 0) return;
1441
1442 bc_num_expand(n, ULONG_NUM_BUFSIZE);
1443
1444 ptr = n->num;
1445 for (;;) {
1446 n->len++;
1447 *ptr++ = val % 10;
1448 val /= 10;
1449 if (val == 0) break;
1450 }
1451}
1452
1453static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b, size_t len)
1454{
1455 size_t i, j;
1456 for (i = 0; i < len; ++i) {
1457 a[i] -= b[i];
1458 for (j = i; a[j] < 0;) {
1459 a[j++] += 10;
1460 a[j] -= 1;
1461 }
1462 }
1463}
1464
1465static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1466{
1467 size_t i = len;
1468 for (;;) {
1469 int c;
1470 if (i == 0)
1471 return 0;
1472 i--;
1473 c = a[i] - b[i];
1474 if (c != 0) {
1475 i++;
1476 if (c < 0)
1477 return -i;
1478 return i;
1479 }
1480 }
1481}
1482
1483#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
1484#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
1485#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
1486
1487static size_t BC_NUM_AREQ(BcNum *a, BcNum *b)
1488{
1489 return BC_MAX(a->rdx, b->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
1490}
1491
1492static size_t BC_NUM_MREQ(BcNum *a, BcNum *b, size_t scale)
1493{
1494 return BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX(scale, a->rdx + b->rdx) + 1;
1495}
1496
1497static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1498{
1499 size_t i, min, a_int, b_int, diff;
1500 BcDig *max_num, *min_num;
1501 bool a_max, neg;
1502 ssize_t cmp;
1503
1504 if (a == b) return 0;
1505 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1506 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1507
1508 if (a->neg != b->neg)
1509
1510 return (int)b->neg - (int)a->neg;
1511 neg = a->neg;
1512
1513 a_int = BC_NUM_INT(a);
1514 b_int = BC_NUM_INT(b);
1515 a_int -= b_int;
1516
1517 if (a_int != 0) {
1518 if (neg) return - (ssize_t) a_int;
1519 return (ssize_t) a_int;
1520 }
1521
1522 a_max = (a->rdx > b->rdx);
1523 if (a_max) {
1524 min = b->rdx;
1525 diff = a->rdx - b->rdx;
1526 max_num = a->num + diff;
1527 min_num = b->num;
1528
1529 } else {
1530 min = a->rdx;
1531 diff = b->rdx - a->rdx;
1532 max_num = b->num + diff;
1533 min_num = a->num;
1534 neg = !neg;
1535 }
1536
1537 cmp = bc_num_compare(max_num, min_num, b_int + min);
1538 if (cmp != 0) return BC_NUM_NEG(cmp, neg);
1539
1540 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1541 if (max_num[i]) return BC_NUM_NEG(1, neg);
1542 }
1543
1544 return 0;
1545}
1546
1547static void bc_num_truncate(BcNum *n, size_t places)
1548{
1549 if (places == 0) return;
1550
1551 n->rdx -= places;
1552
1553 if (n->len != 0) {
1554 n->len -= places;
1555 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1556 }
1557}
1558
1559static void bc_num_extend(BcNum *n, size_t places)
1560{
1561 size_t len = n->len + places;
1562
1563 if (places != 0) {
1564 if (n->cap < len) bc_num_expand(n, len);
1565
1566 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1567 memset(n->num, 0, sizeof(BcDig) * places);
1568
1569 n->len += places;
1570 n->rdx += places;
1571 }
1572}
1573
1574static void bc_num_clean(BcNum *n)
1575{
1576 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1577 if (n->len == 0)
1578 n->neg = false;
1579 else if (n->len < n->rdx)
1580 n->len = n->rdx;
1581}
1582
1583static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1584{
1585 if (n->rdx < scale)
1586 bc_num_extend(n, scale - n->rdx);
1587 else
1588 bc_num_truncate(n, n->rdx - scale);
1589
1590 bc_num_clean(n);
1591 if (n->len != 0) n->neg = !neg1 != !neg2;
1592}
1593
1594static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1595 BcNum *restrict b)
1596{
1597 if (idx < n->len) {
1598 b->len = n->len - idx;
1599 a->len = idx;
1600 a->rdx = b->rdx = 0;
1601
1602 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1603 memcpy(a->num, n->num, idx * sizeof(BcDig));
1604 } else {
1605 bc_num_zero(b);
1606 bc_num_copy(a, n);
1607 }
1608
1609 bc_num_clean(a);
1610 bc_num_clean(b);
1611}
1612
1613static BC_STATUS zbc_num_shift(BcNum *n, size_t places)
1614{
1615 if (places == 0 || n->len == 0) RETURN_STATUS(BC_STATUS_SUCCESS);
1616
1617
1618 if (SIZE_MAX > (BC_MAX_NUM | 0xff)) {
1619 if (places + n->len > BC_MAX_NUM)
1620 RETURN_STATUS(bc_error("number too long: must be [1,"BC_MAX_NUM_STR"]"));
1621 }
1622
1623 if (n->rdx >= places)
1624 n->rdx -= places;
1625 else {
1626 bc_num_extend(n, places - n->rdx);
1627 n->rdx = 0;
1628 }
1629
1630 bc_num_clean(n);
1631
1632 RETURN_STATUS(BC_STATUS_SUCCESS);
1633}
1634#define zbc_num_shift(...) (zbc_num_shift(__VA_ARGS__) COMMA_SUCCESS)
1635
1636typedef BC_STATUS (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t) FAST_FUNC;
1637
1638static BC_STATUS zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1639 BcNumBinaryOp op, size_t req)
1640{
1641 BcStatus s;
1642 BcNum num2, *ptr_a, *ptr_b;
1643 bool init = false;
1644
1645 if (c == a) {
1646 ptr_a = &num2;
1647 memcpy(ptr_a, c, sizeof(BcNum));
1648 init = true;
1649 } else
1650 ptr_a = a;
1651
1652 if (c == b) {
1653 ptr_b = &num2;
1654 if (c != a) {
1655 memcpy(ptr_b, c, sizeof(BcNum));
1656 init = true;
1657 }
1658 } else
1659 ptr_b = b;
1660
1661 if (init)
1662 bc_num_init(c, req);
1663 else
1664 bc_num_expand(c, req);
1665
1666 s = BC_STATUS_SUCCESS;
1667 IF_ERROR_RETURN_POSSIBLE(s =) op(ptr_a, ptr_b, c, scale);
1668
1669 if (init) bc_num_free(&num2);
1670
1671 RETURN_STATUS(s);
1672}
1673#define zbc_num_binary(...) (zbc_num_binary(__VA_ARGS__) COMMA_SUCCESS)
1674
1675static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1676static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1677static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1678static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1679static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1680static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1681
1682static FAST_FUNC BC_STATUS zbc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1683{
1684 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_a : zbc_num_s;
1685 (void) scale;
1686 RETURN_STATUS(zbc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b)));
1687}
1688
1689static FAST_FUNC BC_STATUS zbc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1690{
1691 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_s : zbc_num_a;
1692 (void) scale;
1693 RETURN_STATUS(zbc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b)));
1694}
1695
1696static FAST_FUNC BC_STATUS zbc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1697{
1698 size_t req = BC_NUM_MREQ(a, b, scale);
1699 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_m, req));
1700}
1701
1702static FAST_FUNC BC_STATUS zbc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1703{
1704 size_t req = BC_NUM_MREQ(a, b, scale);
1705 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_d, req));
1706}
1707
1708static FAST_FUNC BC_STATUS zbc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1709{
1710 size_t req = BC_NUM_MREQ(a, b, scale);
1711 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_rem, req));
1712}
1713
1714static FAST_FUNC BC_STATUS zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1715{
1716 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_p, a->len * b->len + 1));
1717}
1718
1719static const BcNumBinaryOp zxc_program_ops[] = {
1720 zbc_num_pow, zbc_num_mul, zbc_num_div, zbc_num_mod, zbc_num_add, zbc_num_sub,
1721};
1722#define zbc_num_add(...) (zbc_num_add(__VA_ARGS__) COMMA_SUCCESS)
1723#define zbc_num_sub(...) (zbc_num_sub(__VA_ARGS__) COMMA_SUCCESS)
1724#define zbc_num_mul(...) (zbc_num_mul(__VA_ARGS__) COMMA_SUCCESS)
1725#define zbc_num_div(...) (zbc_num_div(__VA_ARGS__) COMMA_SUCCESS)
1726#define zbc_num_mod(...) (zbc_num_mod(__VA_ARGS__) COMMA_SUCCESS)
1727#define zbc_num_pow(...) (zbc_num_pow(__VA_ARGS__) COMMA_SUCCESS)
1728
1729static BC_STATUS zbc_num_inv(BcNum *a, BcNum *b, size_t scale)
1730{
1731 BcNum one;
1732 BcDig num[2];
1733
1734 one.cap = 2;
1735 one.num = num;
1736 bc_num_one(&one);
1737
1738 RETURN_STATUS(zbc_num_div(&one, a, b, scale));
1739}
1740#define zbc_num_inv(...) (zbc_num_inv(__VA_ARGS__) COMMA_SUCCESS)
1741
1742static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1743{
1744 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1745 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1746 unsigned carry;
1747
1748
1749
1750
1751 if (a->len == 0) {
1752 bc_num_copy(c, b);
1753 if (sub && c->len) c->neg = !c->neg;
1754 RETURN_STATUS(BC_STATUS_SUCCESS);
1755 }
1756 if (b->len == 0) {
1757 bc_num_copy(c, a);
1758 RETURN_STATUS(BC_STATUS_SUCCESS);
1759 }
1760
1761 c->neg = a->neg;
1762 c->rdx = BC_MAX(a->rdx, b->rdx);
1763 min_rdx = BC_MIN(a->rdx, b->rdx);
1764 c->len = 0;
1765
1766 if (a->rdx > b->rdx) {
1767 diff = a->rdx - b->rdx;
1768 ptr = a->num;
1769 ptr_a = a->num + diff;
1770 ptr_b = b->num;
1771 } else {
1772 diff = b->rdx - a->rdx;
1773 ptr = b->num;
1774 ptr_a = a->num;
1775 ptr_b = b->num + diff;
1776 }
1777
1778 ptr_c = c->num;
1779 for (i = 0; i < diff; ++i, ++c->len)
1780 ptr_c[i] = ptr[i];
1781
1782 ptr_c += diff;
1783 a_int = BC_NUM_INT(a);
1784 b_int = BC_NUM_INT(b);
1785
1786 if (a_int > b_int) {
1787 min_int = b_int;
1788 max = a_int;
1789 ptr = ptr_a;
1790 } else {
1791 min_int = a_int;
1792 max = b_int;
1793 ptr = ptr_b;
1794 }
1795
1796 carry = 0;
1797 for (i = 0; i < min_rdx + min_int; ++i) {
1798 unsigned in = (unsigned)ptr_a[i] + (unsigned)ptr_b[i] + carry;
1799 carry = in / 10;
1800 ptr_c[i] = (BcDig)(in % 10);
1801 }
1802 for (; i < max + min_rdx; ++i) {
1803 unsigned in = (unsigned)ptr[i] + carry;
1804 carry = in / 10;
1805 ptr_c[i] = (BcDig)(in % 10);
1806 }
1807 c->len += i;
1808
1809 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1810
1811 RETURN_STATUS(BC_STATUS_SUCCESS);
1812}
1813
1814static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1815{
1816 ssize_t cmp;
1817 BcNum *minuend, *subtrahend;
1818 size_t start;
1819 bool aneg, bneg, neg;
1820
1821
1822
1823
1824 if (a->len == 0) {
1825 bc_num_copy(c, b);
1826 if (sub && c->len) c->neg = !c->neg;
1827 RETURN_STATUS(BC_STATUS_SUCCESS);
1828 }
1829 if (b->len == 0) {
1830 bc_num_copy(c, a);
1831 RETURN_STATUS(BC_STATUS_SUCCESS);
1832 }
1833
1834 aneg = a->neg;
1835 bneg = b->neg;
1836 a->neg = b->neg = false;
1837
1838 cmp = bc_num_cmp(a, b);
1839
1840 a->neg = aneg;
1841 b->neg = bneg;
1842
1843 if (cmp == 0) {
1844 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1845 RETURN_STATUS(BC_STATUS_SUCCESS);
1846 }
1847 if (cmp > 0) {
1848 neg = a->neg;
1849 minuend = a;
1850 subtrahend = b;
1851 } else {
1852 neg = b->neg;
1853 if (sub) neg = !neg;
1854 minuend = b;
1855 subtrahend = a;
1856 }
1857
1858 bc_num_copy(c, minuend);
1859 c->neg = neg;
1860
1861 if (c->rdx < subtrahend->rdx) {
1862 bc_num_extend(c, subtrahend->rdx - c->rdx);
1863 start = 0;
1864 } else
1865 start = c->rdx - subtrahend->rdx;
1866
1867 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1868
1869 bc_num_clean(c);
1870
1871 RETURN_STATUS(BC_STATUS_SUCCESS);
1872}
1873
1874static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1875 BcNum *restrict c)
1876#define zbc_num_k(...) (zbc_num_k(__VA_ARGS__) COMMA_SUCCESS)
1877{
1878 BcStatus s;
1879 size_t max, max2;
1880 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1881 bool aone;
1882
1883 if (a->len == 0 || b->len == 0) {
1884 bc_num_zero(c);
1885 RETURN_STATUS(BC_STATUS_SUCCESS);
1886 }
1887 aone = BC_NUM_ONE(a);
1888 if (aone || BC_NUM_ONE(b)) {
1889 bc_num_copy(c, aone ? b : a);
1890 RETURN_STATUS(BC_STATUS_SUCCESS);
1891 }
1892
1893 if (a->len < BC_NUM_KARATSUBA_LEN
1894 || b->len < BC_NUM_KARATSUBA_LEN
1895
1896 ) {
1897 size_t i, j, len;
1898
1899 bc_num_expand(c, a->len + b->len + 1);
1900
1901 memset(c->num, 0, sizeof(BcDig) * c->cap);
1902 c->len = len = 0;
1903
1904 for (i = 0; i < b->len; ++i) {
1905 unsigned carry = 0;
1906 for (j = 0; j < a->len; ++j) {
1907 unsigned in = c->num[i + j];
1908 in += (unsigned)a->num[j] * (unsigned)b->num[i] + carry;
1909
1910 carry = in / 10;
1911 c->num[i + j] = (BcDig)(in % 10);
1912 }
1913
1914 c->num[i + j] += (BcDig) carry;
1915 len = BC_MAX(len, i + j + !!carry);
1916
1917#if ENABLE_FEATURE_BC_INTERACTIVE
1918
1919
1920 if (G_interrupt) return BC_STATUS_FAILURE;
1921#endif
1922 }
1923
1924 c->len = len;
1925
1926 RETURN_STATUS(BC_STATUS_SUCCESS);
1927 }
1928
1929 max = BC_MAX(a->len, b->len);
1930 bc_num_init(&l1, max);
1931 bc_num_init(&h1, max);
1932 bc_num_init(&l2, max);
1933 bc_num_init(&h2, max);
1934 bc_num_init(&m1, max);
1935 bc_num_init(&m2, max);
1936 bc_num_init(&z0, max);
1937 bc_num_init(&z1, max);
1938 bc_num_init(&z2, max);
1939 bc_num_init(&temp, max + max);
1940
1941 max2 = (max + 1) / 2;
1942 bc_num_split(a, max2, &l1, &h1);
1943 bc_num_split(b, max2, &l2, &h2);
1944
1945 s = zbc_num_add(&h1, &l1, &m1, 0);
1946 if (s) goto err;
1947 s = zbc_num_add(&h2, &l2, &m2, 0);
1948 if (s) goto err;
1949
1950 s = zbc_num_k(&h1, &h2, &z0);
1951 if (s) goto err;
1952 s = zbc_num_k(&m1, &m2, &z1);
1953 if (s) goto err;
1954 s = zbc_num_k(&l1, &l2, &z2);
1955 if (s) goto err;
1956
1957 s = zbc_num_sub(&z1, &z0, &temp, 0);
1958 if (s) goto err;
1959 s = zbc_num_sub(&temp, &z2, &z1, 0);
1960 if (s) goto err;
1961
1962 s = zbc_num_shift(&z0, max2 * 2);
1963 if (s) goto err;
1964 s = zbc_num_shift(&z1, max2);
1965 if (s) goto err;
1966 s = zbc_num_add(&z0, &z1, &temp, 0);
1967 if (s) goto err;
1968 s = zbc_num_add(&temp, &z2, c, 0);
1969 err:
1970 bc_num_free(&temp);
1971 bc_num_free(&z2);
1972 bc_num_free(&z1);
1973 bc_num_free(&z0);
1974 bc_num_free(&m2);
1975 bc_num_free(&m1);
1976 bc_num_free(&h2);
1977 bc_num_free(&l2);
1978 bc_num_free(&h1);
1979 bc_num_free(&l1);
1980 RETURN_STATUS(s);
1981}
1982
1983static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1984{
1985 BcStatus s;
1986 BcNum cpa, cpb;
1987 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1988
1989 scale = BC_MAX(scale, a->rdx);
1990 scale = BC_MAX(scale, b->rdx);
1991 scale = BC_MIN(a->rdx + b->rdx, scale);
1992 maxrdx = BC_MAX(maxrdx, scale);
1993
1994 bc_num_init_and_copy(&cpa, a);
1995 bc_num_init_and_copy(&cpb, b);
1996 cpa.neg = cpb.neg = false;
1997
1998 s = zbc_num_shift(&cpa, maxrdx);
1999 if (s) goto err;
2000 s = zbc_num_shift(&cpb, maxrdx);
2001 if (s) goto err;
2002 s = zbc_num_k(&cpa, &cpb, c);
2003 if (s) goto err;
2004
2005 maxrdx += scale;
2006 bc_num_expand(c, c->len + maxrdx);
2007
2008 if (c->len < maxrdx) {
2009 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
2010 c->len += maxrdx;
2011 }
2012
2013 c->rdx = maxrdx;
2014 bc_num_retireMul(c, scale, a->neg, b->neg);
2015 err:
2016 bc_num_free(&cpb);
2017 bc_num_free(&cpa);
2018 RETURN_STATUS(s);
2019}
2020#define zbc_num_m(...) (zbc_num_m(__VA_ARGS__) COMMA_SUCCESS)
2021
2022static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2023{
2024 BcStatus s;
2025 size_t len, end, i;
2026 BcNum cp;
2027
2028 if (b->len == 0)
2029 RETURN_STATUS(bc_error("divide by zero"));
2030 if (a->len == 0) {
2031 bc_num_setToZero(c, scale);
2032 RETURN_STATUS(BC_STATUS_SUCCESS);
2033 }
2034 if (BC_NUM_ONE(b)) {
2035 bc_num_copy(c, a);
2036 bc_num_retireMul(c, scale, a->neg, b->neg);
2037 RETURN_STATUS(BC_STATUS_SUCCESS);
2038 }
2039
2040 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
2041 bc_num_copy(&cp, a);
2042 len = b->len;
2043
2044 if (len > cp.len) {
2045 bc_num_expand(&cp, len + 2);
2046 bc_num_extend(&cp, len - cp.len);
2047 }
2048
2049 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
2050 cp.rdx -= b->rdx;
2051 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
2052
2053 if (b->rdx == b->len) {
2054 for (;;) {
2055 if (len == 0) break;
2056 len--;
2057 if (b->num[len] != 0)
2058 break;
2059 }
2060 len++;
2061 }
2062
2063 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
2064
2065
2066 cp.num[cp.len++] = 0;
2067 end = cp.len - len;
2068
2069 bc_num_expand(c, cp.len);
2070
2071 bc_num_zero(c);
2072 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
2073 c->rdx = cp.rdx;
2074 c->len = cp.len;
2075
2076 s = BC_STATUS_SUCCESS;
2077 for (i = end - 1; i < end; --i) {
2078 BcDig *n, q;
2079 n = cp.num + i;
2080 for (q = 0; n[len] != 0 || bc_num_compare(n, b->num, len) >= 0; ++q)
2081 bc_num_subArrays(n, b->num, len);
2082 c->num[i] = q;
2083#if ENABLE_FEATURE_BC_INTERACTIVE
2084
2085
2086
2087 if (G_interrupt) {
2088 s = BC_STATUS_FAILURE;
2089 break;
2090 }
2091#endif
2092 }
2093
2094 bc_num_retireMul(c, scale, a->neg, b->neg);
2095 bc_num_free(&cp);
2096
2097 RETURN_STATUS(s);
2098}
2099#define zbc_num_d(...) (zbc_num_d(__VA_ARGS__) COMMA_SUCCESS)
2100
2101static FAST_FUNC BC_STATUS zbc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
2102 BcNum *restrict d, size_t scale, size_t ts)
2103{
2104 BcStatus s;
2105 BcNum temp;
2106 bool neg;
2107
2108 if (b->len == 0)
2109 RETURN_STATUS(bc_error("divide by zero"));
2110
2111 if (a->len == 0) {
2112 bc_num_setToZero(d, ts);
2113 RETURN_STATUS(BC_STATUS_SUCCESS);
2114 }
2115
2116 bc_num_init(&temp, d->cap);
2117 s = zbc_num_d(a, b, c, scale);
2118 if (s) goto err;
2119
2120 if (scale != 0) scale = ts;
2121
2122 s = zbc_num_m(c, b, &temp, scale);
2123 if (s) goto err;
2124 s = zbc_num_sub(a, &temp, d, scale);
2125 if (s) goto err;
2126
2127 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2128
2129 neg = d->neg;
2130 bc_num_retireMul(d, ts, a->neg, b->neg);
2131 d->neg = neg;
2132 err:
2133 bc_num_free(&temp);
2134 RETURN_STATUS(s);
2135}
2136#define zbc_num_r(...) (zbc_num_r(__VA_ARGS__) COMMA_SUCCESS)
2137
2138static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2139{
2140 BcStatus s;
2141 BcNum c1;
2142 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2143
2144 bc_num_init(&c1, len);
2145 s = zbc_num_r(a, b, &c1, c, scale, ts);
2146 bc_num_free(&c1);
2147
2148 RETURN_STATUS(s);
2149}
2150#define zbc_num_rem(...) (zbc_num_rem(__VA_ARGS__) COMMA_SUCCESS)
2151
2152static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2153{
2154 BcStatus s = BC_STATUS_SUCCESS;
2155 BcNum copy;
2156 unsigned long pow;
2157 size_t i, powrdx, resrdx;
2158 size_t a_rdx;
2159 bool neg;
2160
2161
2162 for (i = 0; i < b->rdx; i++)
2163 if (b->num[i] != 0)
2164 RETURN_STATUS(bc_error("not an integer"));
2165
2166
2167
2168
2169 if (b->len == 0) {
2170 bc_num_one(c);
2171 RETURN_STATUS(BC_STATUS_SUCCESS);
2172 }
2173 if (a->len == 0) {
2174 bc_num_setToZero(c, scale);
2175 RETURN_STATUS(BC_STATUS_SUCCESS);
2176 }
2177 if (BC_NUM_ONE(b)) {
2178 if (!b->neg)
2179 bc_num_copy(c, a);
2180 else
2181 s = zbc_num_inv(a, c, scale);
2182 RETURN_STATUS(s);
2183 }
2184
2185 neg = b->neg;
2186 s = zbc_num_ulong_abs(b, &pow);
2187 if (s) RETURN_STATUS(s);
2188
2189
2190 bc_num_init_and_copy(©, a);
2191 a_rdx = a->rdx;
2192
2193
2194 if (!neg) {
2195 unsigned long new_scale;
2196 if (a_rdx > scale)
2197 scale = a_rdx;
2198 new_scale = a_rdx * pow;
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209 if (a_rdx == 0 || new_scale >= pow)
2210 if (new_scale < scale)
2211 scale = new_scale;
2212 }
2213
2214 for (powrdx = a_rdx; !(pow & 1); pow >>= 1) {
2215 powrdx <<= 1;
2216 s = zbc_num_mul(©, ©, ©, powrdx);
2217 if (s) goto err;
2218
2219
2220
2221
2222
2223 }
2224
2225 bc_num_copy(c, ©);
2226
2227 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2228 powrdx <<= 1;
2229 s = zbc_num_mul(©, ©, ©, powrdx);
2230 if (s) goto err;
2231
2232 if (pow & 1) {
2233 resrdx += powrdx;
2234 s = zbc_num_mul(c, ©, c, resrdx);
2235 if (s) goto err;
2236 }
2237
2238
2239
2240
2241
2242 }
2243
2244 if (neg) {
2245 s = zbc_num_inv(c, c, scale);
2246 if (s) goto err;
2247 }
2248
2249 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2250
2251
2252 for (i = 0; i < c->len; ++i)
2253 if (c->num[i] != 0)
2254 goto skip;
2255 bc_num_setToZero(c, scale);
2256 skip:
2257
2258 err:
2259 bc_num_free(©);
2260 RETURN_STATUS(s);
2261}
2262#define zbc_num_p(...) (zbc_num_p(__VA_ARGS__) COMMA_SUCCESS)
2263
2264static NOINLINE BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2265{
2266 BcStatus s;
2267 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2268 BcDig half_digs[1];
2269 size_t pow, len, digs, digs1, resrdx, req, times;
2270 ssize_t cmp, cmp1, cmp2;
2271
2272 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2273 bc_num_expand(b, req);
2274
2275 if (a->len == 0) {
2276 bc_num_setToZero(b, scale);
2277 RETURN_STATUS(BC_STATUS_SUCCESS);
2278 }
2279 if (a->neg) {
2280 RETURN_STATUS(bc_error("negative number"));
2281 }
2282 if (BC_NUM_ONE(a)) {
2283 bc_num_one(b);
2284 bc_num_extend(b, scale);
2285 RETURN_STATUS(BC_STATUS_SUCCESS);
2286 }
2287
2288 scale = BC_MAX(scale, a->rdx) + 1;
2289 len = a->len + scale;
2290
2291 bc_num_init(&num1, len);
2292 bc_num_init(&num2, len);
2293
2294 half.cap = ARRAY_SIZE(half_digs);
2295 half.num = half_digs;
2296 bc_num_one(&half);
2297 half_digs[0] = 5;
2298 half.rdx = 1;
2299
2300 bc_num_init(&f, len);
2301 bc_num_init(&fprime, len);
2302
2303 x0 = &num1;
2304 x1 = &num2;
2305
2306 bc_num_one(x0);
2307 pow = BC_NUM_INT(a);
2308
2309 if (pow) {
2310 if (pow & 1)
2311 x0->num[0] = 2;
2312 else
2313 x0->num[0] = 6;
2314
2315 pow -= 2 - (pow & 1);
2316
2317 bc_num_extend(x0, pow);
2318
2319
2320 x0->rdx -= pow;
2321 }
2322
2323 x0->rdx = digs = digs1 = times = 0;
2324 resrdx = scale + 2;
2325 len = x0->len + resrdx - 1;
2326 cmp = 1;
2327 cmp1 = cmp2 = SSIZE_MAX;
2328 do {
2329 s = zbc_num_div(a, x0, &f, resrdx);
2330 if (s) goto err;
2331 s = zbc_num_add(x0, &f, &fprime, resrdx);
2332 if (s) goto err;
2333 s = zbc_num_mul(&fprime, &half, x1, resrdx);
2334 if (s) goto err;
2335
2336 cmp = bc_num_cmp(x1, x0);
2337 digs = x1->len - (unsigned long long) llabs(cmp);
2338
2339 if (cmp == cmp2 && digs == digs1)
2340 times += 1;
2341 else
2342 times = 0;
2343
2344 resrdx += times > 4;
2345
2346 cmp2 = cmp1;
2347 cmp1 = cmp;
2348 digs1 = digs;
2349
2350 temp = x0;
2351 x0 = x1;
2352 x1 = temp;
2353 } while (cmp != 0 || digs < len);
2354
2355 bc_num_copy(b, x0);
2356 scale -= 1;
2357 if (b->rdx > scale)
2358 bc_num_truncate(b, b->rdx - scale);
2359 err:
2360 bc_num_free(&fprime);
2361 bc_num_free(&f);
2362 bc_num_free(&num2);
2363 bc_num_free(&num1);
2364 RETURN_STATUS(s);
2365}
2366#define zbc_num_sqrt(...) (zbc_num_sqrt(__VA_ARGS__) COMMA_SUCCESS)
2367
2368static BC_STATUS zbc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2369 size_t scale)
2370{
2371 BcStatus s;
2372 BcNum num2, *ptr_a;
2373 bool init = false;
2374 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2375
2376 if (c == a) {
2377 memcpy(&num2, c, sizeof(BcNum));
2378 ptr_a = &num2;
2379 bc_num_init(c, len);
2380 init = true;
2381 } else {
2382 ptr_a = a;
2383 bc_num_expand(c, len);
2384 }
2385
2386 s = zbc_num_r(ptr_a, b, c, d, scale, ts);
2387
2388 if (init) bc_num_free(&num2);
2389
2390 RETURN_STATUS(s);
2391}
2392#define zbc_num_divmod(...) (zbc_num_divmod(__VA_ARGS__) COMMA_SUCCESS)
2393
2394#if ENABLE_DC
2395static BC_STATUS zdc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2396{
2397 BcStatus s;
2398 BcNum base, exp, two, temp;
2399 BcDig two_digs[1];
2400
2401 if (c->len == 0)
2402 RETURN_STATUS(bc_error("divide by zero"));
2403 if (a->rdx || b->rdx || c->rdx)
2404 RETURN_STATUS(bc_error("not an integer"));
2405 if (b->neg)
2406 RETURN_STATUS(bc_error("negative number"));
2407
2408 bc_num_expand(d, c->len);
2409 bc_num_init(&base, c->len);
2410 bc_num_init(&exp, b->len);
2411 bc_num_init(&temp, b->len);
2412
2413 two.cap = ARRAY_SIZE(two_digs);
2414 two.num = two_digs;
2415 bc_num_one(&two);
2416 two_digs[0] = 2;
2417
2418 bc_num_one(d);
2419
2420 s = zbc_num_rem(a, c, &base, 0);
2421 if (s) goto err;
2422 bc_num_copy(&exp, b);
2423
2424 while (exp.len != 0) {
2425 s = zbc_num_divmod(&exp, &two, &exp, &temp, 0);
2426 if (s) goto err;
2427
2428 if (BC_NUM_ONE(&temp)) {
2429 s = zbc_num_mul(d, &base, &temp, 0);
2430 if (s) goto err;
2431 s = zbc_num_rem(&temp, c, d, 0);
2432 if (s) goto err;
2433 }
2434
2435 s = zbc_num_mul(&base, &base, &temp, 0);
2436 if (s) goto err;
2437 s = zbc_num_rem(&temp, c, &base, 0);
2438 if (s) goto err;
2439 }
2440 err:
2441 bc_num_free(&temp);
2442 bc_num_free(&exp);
2443 bc_num_free(&base);
2444 RETURN_STATUS(s);
2445}
2446#define zdc_num_modexp(...) (zdc_num_modexp(__VA_ARGS__) COMMA_SUCCESS)
2447#endif
2448
2449static FAST_FUNC void bc_string_free(void *string)
2450{
2451 free(*(char**)string);
2452}
2453
2454static void bc_func_init(BcFunc *f)
2455{
2456 bc_char_vec_init(&f->code);
2457 IF_BC(bc_vec_init(&f->labels, sizeof(size_t), NULL);)
2458 IF_BC(bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);)
2459 IF_BC(bc_vec_init(&f->strs, sizeof(char *), bc_string_free);)
2460 IF_BC(bc_vec_init(&f->consts, sizeof(char *), bc_string_free);)
2461 IF_BC(f->nparams = 0;)
2462}
2463
2464static FAST_FUNC void bc_func_free(void *func)
2465{
2466 BcFunc *f = (BcFunc *) func;
2467 bc_vec_free(&f->code);
2468 IF_BC(bc_vec_free(&f->labels);)
2469 IF_BC(bc_vec_free(&f->autos);)
2470 IF_BC(bc_vec_free(&f->strs);)
2471 IF_BC(bc_vec_free(&f->consts);)
2472}
2473
2474static void bc_array_expand(BcVec *a, size_t len);
2475
2476static void bc_array_init(BcVec *a, bool nums)
2477{
2478 if (nums)
2479 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2480 else
2481 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2482 bc_array_expand(a, 1);
2483}
2484
2485static void bc_array_expand(BcVec *a, size_t len)
2486{
2487 if (a->dtor == bc_num_free
2488
2489 ) {
2490 BcNum n;
2491 while (len > a->len) {
2492 bc_num_init_DEF_SIZE(&n);
2493 bc_vec_push(a, &n);
2494 }
2495 } else {
2496 BcVec v;
2497 while (len > a->len) {
2498 bc_array_init(&v, true);
2499 bc_vec_push(a, &v);
2500 }
2501 }
2502}
2503
2504static void bc_array_copy(BcVec *d, const BcVec *s)
2505{
2506 BcNum *dnum, *snum;
2507 size_t i;
2508
2509 bc_vec_pop_all(d);
2510 bc_vec_expand(d, s->cap);
2511 d->len = s->len;
2512
2513 dnum = (void*)d->v;
2514 snum = (void*)s->v;
2515 for (i = 0; i < s->len; i++, dnum++, snum++) {
2516 bc_num_init_and_copy(dnum, snum);
2517 }
2518}
2519
2520#if ENABLE_DC
2521static void dc_result_copy(BcResult *d, BcResult *src)
2522{
2523 d->t = src->t;
2524
2525 switch (d->t) {
2526 case XC_RESULT_TEMP:
2527 case XC_RESULT_IBASE:
2528 case XC_RESULT_SCALE:
2529 case XC_RESULT_OBASE:
2530 bc_num_init_and_copy(&d->d.n, &src->d.n);
2531 break;
2532 case XC_RESULT_VAR:
2533 case XC_RESULT_ARRAY:
2534 case XC_RESULT_ARRAY_ELEM:
2535 d->d.id.name = xstrdup(src->d.id.name);
2536 break;
2537 case XC_RESULT_CONSTANT:
2538 case XC_RESULT_STR:
2539 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2540 break;
2541 default:
2542
2543 break;
2544 }
2545}
2546#endif
2547
2548static FAST_FUNC void bc_result_free(void *result)
2549{
2550 BcResult *r = (BcResult *) result;
2551
2552 switch (r->t) {
2553 case XC_RESULT_TEMP:
2554 IF_BC(case BC_RESULT_VOID:)
2555 case XC_RESULT_IBASE:
2556 case XC_RESULT_SCALE:
2557 case XC_RESULT_OBASE:
2558 bc_num_free(&r->d.n);
2559 break;
2560 case XC_RESULT_VAR:
2561 case XC_RESULT_ARRAY:
2562 case XC_RESULT_ARRAY_ELEM:
2563 free(r->d.id.name);
2564 break;
2565 default:
2566
2567 break;
2568 }
2569}
2570
2571static int bad_input_byte(char c)
2572{
2573 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n')
2574 || c > 0x7e
2575 ) {
2576 bc_error_fmt("illegal character 0x%02x", c);
2577 return 1;
2578 }
2579 return 0;
2580}
2581
2582static void xc_read_line(BcVec *vec, FILE *fp)
2583{
2584 again:
2585 bc_vec_pop_all(vec);
2586 fflush_and_check();
2587
2588#if ENABLE_FEATURE_BC_INTERACTIVE
2589 if (G_interrupt) {
2590 if (fp != stdin) {
2591
2592
2593
2594
2595
2596
2597
2598 xfunc_die();
2599 }
2600
2601 G_interrupt = 0;
2602
2603
2604 puts("\ninterrupted execution");
2605 }
2606
2607# if ENABLE_FEATURE_EDITING
2608 if (G_ttyin && fp == stdin) {
2609 int n, i;
2610 if (!G.line_input_state)
2611 G.line_input_state = new_line_input_t(DO_HISTORY);
2612# define line_buf bb_common_bufsiz1
2613 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE);
2614 if (n <= 0) {
2615
2616
2617
2618 bc_vec_pushZeroByte(vec);
2619 return;
2620 }
2621 i = 0;
2622 for (;;) {
2623 char c = line_buf[i++];
2624 if (c == '\0') break;
2625 if (bad_input_byte(c)) goto again;
2626 }
2627 bc_vec_string(vec, n, line_buf);
2628# undef line_buf
2629 } else
2630# endif
2631#endif
2632 {
2633 int c;
2634 bool bad_chars = 0;
2635
2636 do {
2637 get_char:
2638#if ENABLE_FEATURE_BC_INTERACTIVE
2639 if (G_interrupt) {
2640
2641 goto again;
2642 }
2643#endif
2644 c = fgetc(fp);
2645 if (c == '\0')
2646 goto get_char;
2647 if (c == EOF) {
2648 if (ferror(fp))
2649 bb_simple_perror_msg_and_die("input error");
2650
2651 break;
2652 }
2653 bad_chars |= bad_input_byte(c);
2654 bc_vec_pushByte(vec, (char)c);
2655 } while (c != '\n');
2656
2657 if (bad_chars) {
2658
2659 if (!G.prs.lex_filename) {
2660
2661 goto again;
2662 }
2663 bb_perror_msg_and_die("file '%s' is not text", G.prs.lex_filename);
2664 }
2665 bc_vec_pushZeroByte(vec);
2666 }
2667}
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680static bool xc_num_strValid(const char *val)
2681{
2682 bool radix = false;
2683 for (;;) {
2684 BcDig c = *val++;
2685 if (c == '\0')
2686 break;
2687 if (c == '.') {
2688 if (radix) return false;
2689 radix = true;
2690 continue;
2691 }
2692 if ((c < '0' || c > '9') && (c < 'A' || c > 'Z'))
2693 return false;
2694 }
2695 return true;
2696}
2697
2698
2699
2700static void bc_num_parseDecimal(BcNum *n, const char *val)
2701{
2702 size_t len, i;
2703 const char *ptr;
2704
2705 len = strlen(val);
2706 if (len == 0)
2707 return;
2708
2709 bc_num_expand(n, len + 1);
2710
2711 ptr = strchr(val, '.');
2712
2713 n->rdx = 0;
2714 if (ptr != NULL)
2715 n->rdx = (size_t)((val + len) - (ptr + 1));
2716
2717 for (i = 0; val[i]; ++i) {
2718 if (val[i] != '0' && val[i] != '.') {
2719
2720 if (len == 1) {
2721 unsigned c = val[0] - '0';
2722 n->len = 1;
2723 if (c > 9) {
2724 n->len = 2;
2725 c -= ('A' - '9' - 1);
2726 n->num[1] = c/10;
2727 c = c%10;
2728 }
2729 n->num[0] = c;
2730 break;
2731 }
2732 i = len - 1;
2733 for (;;) {
2734 char c = val[i] - '0';
2735 if (c > 9)
2736 c = 9;
2737 n->num[n->len] = c;
2738 n->len++;
2739 skip_dot:
2740 if (i == 0) break;
2741 if (val[--i] == '.') goto skip_dot;
2742 }
2743 break;
2744 }
2745 }
2746
2747}
2748
2749
2750
2751static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
2752{
2753 BcStatus s;
2754 BcNum mult, result;
2755 BcNum temp;
2756 BcNum base;
2757 BcDig temp_digs[ULONG_NUM_BUFSIZE];
2758 BcDig base_digs[ULONG_NUM_BUFSIZE];
2759 size_t digits;
2760
2761 bc_num_init_DEF_SIZE(&mult);
2762
2763 temp.cap = ARRAY_SIZE(temp_digs);
2764 temp.num = temp_digs;
2765
2766 base.cap = ARRAY_SIZE(base_digs);
2767 base.num = base_digs;
2768 bc_num_ulong2num(&base, base_t);
2769 base_t--;
2770
2771 for (;;) {
2772 unsigned v;
2773 char c;
2774
2775 c = *val++;
2776 if (c == '\0') goto int_err;
2777 if (c == '.') break;
2778
2779 v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
2780 if (v > base_t) v = base_t;
2781
2782 s = zbc_num_mul(n, &base, &mult, 0);
2783 if (s) goto int_err;
2784 bc_num_ulong2num(&temp, v);
2785 s = zbc_num_add(&mult, &temp, n, 0);
2786 if (s) goto int_err;
2787 }
2788
2789 bc_num_init(&result, base.len);
2790
2791 bc_num_one(&mult);
2792
2793 digits = 0;
2794 for (;;) {
2795 unsigned v;
2796 char c;
2797
2798 c = *val++;
2799 if (c == '\0') break;
2800 digits++;
2801
2802 v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
2803 if (v > base_t) v = base_t;
2804
2805 s = zbc_num_mul(&result, &base, &result, 0);
2806 if (s) goto err;
2807 bc_num_ulong2num(&temp, v);
2808 s = zbc_num_add(&result, &temp, &result, 0);
2809 if (s) goto err;
2810 s = zbc_num_mul(&mult, &base, &mult, 0);
2811 if (s) goto err;
2812 }
2813
2814 s = zbc_num_div(&result, &mult, &result, digits);
2815 if (s) goto err;
2816 s = zbc_num_add(n, &result, n, digits);
2817 if (s) goto err;
2818
2819 if (n->len != 0) {
2820 if (n->rdx < digits)
2821 bc_num_extend(n, digits - n->rdx);
2822 } else
2823 bc_num_zero(n);
2824 err:
2825 bc_num_free(&result);
2826 int_err:
2827 bc_num_free(&mult);
2828}
2829
2830static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t)
2831{
2832 size_t i;
2833
2834 if (!xc_num_strValid(val))
2835 RETURN_STATUS(bc_error("bad number string"));
2836
2837 bc_num_zero(n);
2838 while (*val == '0')
2839 val++;
2840 for (i = 0; ; ++i) {
2841 if (val[i] == '\0')
2842 RETURN_STATUS(BC_STATUS_SUCCESS);
2843 if (val[i] != '.' && val[i] != '0')
2844 break;
2845 }
2846
2847 if (base_t == 10 || val[1] == '\0')
2848
2849 bc_num_parseDecimal(n, val);
2850 else
2851 bc_num_parseBase(n, val, base_t);
2852
2853 RETURN_STATUS(BC_STATUS_SUCCESS);
2854}
2855#define zxc_num_parse(...) (zxc_num_parse(__VA_ARGS__) COMMA_SUCCESS)
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888static char peek_inbuf(void)
2889{
2890 if (*G.prs.lex_inbuf == '\0'
2891 && G.prs.lex_input_fp
2892 ) {
2893 xc_read_line(&G.input_buffer, G.prs.lex_input_fp);
2894 G.prs.lex_inbuf = G.input_buffer.v;
2895
2896 G.prs.lex_next_at = G.prs.lex_inbuf;
2897 if (G.input_buffer.len <= 1)
2898 G.prs.lex_input_fp = NULL;
2899 }
2900 return *G.prs.lex_inbuf;
2901}
2902static char eat_inbuf(void)
2903{
2904 char c = peek_inbuf();
2905 if (c) G.prs.lex_inbuf++;
2906 return c;
2907}
2908
2909static void xc_lex_lineComment(void)
2910{
2911 BcParse *p = &G.prs;
2912 char c;
2913
2914
2915 p->lex = XC_LEX_WHITESPACE;
2916
2917
2918
2919 while ((c = *p->lex_inbuf) != '\n' && c != '\0')
2920 p->lex_inbuf++;
2921}
2922
2923static void xc_lex_whitespace(void)
2924{
2925 BcParse *p = &G.prs;
2926
2927 p->lex = XC_LEX_WHITESPACE;
2928 for (;;) {
2929
2930
2931 char c = *p->lex_inbuf;
2932 if (c == '\n')
2933 break;
2934 if (!isspace(c))
2935 break;
2936 p->lex_inbuf++;
2937 }
2938}
2939
2940static BC_STATUS zxc_lex_number(char last)
2941{
2942 BcParse *p = &G.prs;
2943 bool pt;
2944 char last_valid_ch;
2945
2946 bc_vec_pop_all(&p->lex_strnumbuf);
2947 bc_vec_pushByte(&p->lex_strnumbuf, last);
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957 last_valid_ch = (IS_BC ? 'Z' : 'F');
2958 pt = (last == '.');
2959 p->lex = XC_LEX_NUMBER;
2960 for (;;) {
2961
2962
2963 char c = *p->lex_inbuf;
2964 check_c:
2965 if (c == '\0')
2966 break;
2967 if (c == '\\' && p->lex_inbuf[1] == '\n') {
2968 p->lex_inbuf += 2;
2969 p->lex_line++;
2970 dbg_lex("++p->lex_line=%zd", p->lex_line);
2971 c = peek_inbuf();
2972 goto check_c;
2973 }
2974 if (!isdigit(c) && (c < 'A' || c > last_valid_ch)) {
2975 if (c != '.') break;
2976
2977 if (pt) break;
2978 pt = true;
2979 }
2980
2981 last = c;
2982 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
2983 p->lex_inbuf++;
2984 }
2985 if (last == '.')
2986 bc_vec_pop(&p->lex_strnumbuf);
2987 bc_vec_pushZeroByte(&p->lex_strnumbuf);
2988
2989 G.err_line = G.prs.lex_line;
2990 RETURN_STATUS(BC_STATUS_SUCCESS);
2991}
2992#define zxc_lex_number(...) (zxc_lex_number(__VA_ARGS__) COMMA_SUCCESS)
2993
2994static void xc_lex_name(void)
2995{
2996 BcParse *p = &G.prs;
2997 size_t i;
2998 const char *buf;
2999
3000 p->lex = XC_LEX_NAME;
3001
3002
3003
3004 i = 0;
3005 buf = p->lex_inbuf - 1;
3006 for (;;) {
3007 char c = buf[i];
3008 if ((c < 'a' || c > 'z') && !isdigit(c) && c != '_') break;
3009 i++;
3010 }
3011
3012#if 0
3013
3014 if (SIZE_MAX > (BC_MAX_STRING | 0xff)) {
3015 if (i > BC_MAX_STRING)
3016 return bc_error("name too long: must be [1,"BC_MAX_STRING_STR"]");
3017 }
3018#endif
3019 bc_vec_string(&p->lex_strnumbuf, i, buf);
3020
3021
3022 p->lex_inbuf += i - 1;
3023
3024
3025}
3026
3027IF_BC(static BC_STATUS zbc_lex_token(void);)
3028IF_DC(static BC_STATUS zdc_lex_token(void);)
3029#define zbc_lex_token(...) (zbc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
3030#define zdc_lex_token(...) (zdc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
3031
3032static BC_STATUS zxc_lex_next(void)
3033{
3034 BcParse *p = &G.prs;
3035 BcStatus s;
3036
3037 G.err_line = p->lex_line;
3038 p->lex_last = p->lex;
3039
3040
3041
3042
3043
3044
3045
3046 s = BC_STATUS_SUCCESS;
3047 do {
3048 if (*p->lex_inbuf == '\0') {
3049 p->lex = XC_LEX_EOF;
3050 if (peek_inbuf() == '\0')
3051 RETURN_STATUS(BC_STATUS_SUCCESS);
3052 }
3053 p->lex_next_at = p->lex_inbuf;
3054 dbg_lex("next string to parse:'%.*s'",
3055 (int)(strchrnul(p->lex_next_at, '\n') - p->lex_next_at),
3056 p->lex_next_at
3057 );
3058 if (IS_BC) {
3059 IF_BC(s = zbc_lex_token());
3060 } else {
3061 IF_DC(s = zdc_lex_token());
3062 }
3063 } while (!s && p->lex == XC_LEX_WHITESPACE);
3064 dbg_lex("p->lex from string:%d", p->lex);
3065
3066 RETURN_STATUS(s);
3067}
3068#define zxc_lex_next(...) (zxc_lex_next(__VA_ARGS__) COMMA_SUCCESS)
3069
3070#if ENABLE_BC
3071static BC_STATUS zbc_lex_skip_if_at_NLINE(void)
3072{
3073 if (G.prs.lex == XC_LEX_NLINE)
3074 RETURN_STATUS(zxc_lex_next());
3075 RETURN_STATUS(BC_STATUS_SUCCESS);
3076}
3077#define zbc_lex_skip_if_at_NLINE(...) (zbc_lex_skip_if_at_NLINE(__VA_ARGS__) COMMA_SUCCESS)
3078
3079static BC_STATUS zbc_lex_next_and_skip_NLINE(void)
3080{
3081 BcStatus s;
3082 s = zxc_lex_next();
3083 if (s) RETURN_STATUS(s);
3084
3085 s = zbc_lex_skip_if_at_NLINE();
3086 RETURN_STATUS(s);
3087}
3088#define zbc_lex_next_and_skip_NLINE(...) (zbc_lex_next_and_skip_NLINE(__VA_ARGS__) COMMA_SUCCESS)
3089
3090static BC_STATUS zbc_lex_identifier(void)
3091{
3092 BcParse *p = &G.prs;
3093 BcStatus s;
3094 unsigned i;
3095 const char *buf = p->lex_inbuf - 1;
3096
3097 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
3098 const char *keyword8 = bc_lex_kws[i].name8;
3099 unsigned j = 0;
3100 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
3101 j++;
3102 if (j == 8) goto match;
3103 }
3104 if (keyword8[j] != '\0')
3105 continue;
3106 match:
3107
3108 if (isalnum(buf[j]) || buf[j] == '_')
3109 continue;
3110 p->lex = BC_LEX_KEY_1st_keyword + i;
3111 if (!keyword_is_POSIX(i)) {
3112 s = zbc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
3113 if (s) RETURN_STATUS(s);
3114 }
3115
3116
3117 p->lex_inbuf += j - 1;
3118 RETURN_STATUS(BC_STATUS_SUCCESS);
3119 }
3120
3121 xc_lex_name();
3122 s = BC_STATUS_SUCCESS;
3123
3124 if (p->lex_strnumbuf.len > 2) {
3125
3126
3127
3128
3129 unsigned len = strchrnul(buf, '\n') - buf;
3130 s = zbc_posix_error_fmt("POSIX only allows one character names; this is bad: '%.*s'", len, buf);
3131 }
3132
3133 RETURN_STATUS(s);
3134}
3135#define zbc_lex_identifier(...) (zbc_lex_identifier(__VA_ARGS__) COMMA_SUCCESS)
3136
3137static BC_STATUS zbc_lex_string(void)
3138{
3139 BcParse *p = &G.prs;
3140
3141 p->lex = XC_LEX_STR;
3142 bc_vec_pop_all(&p->lex_strnumbuf);
3143 for (;;) {
3144 char c = peek_inbuf();
3145 if (c == '\0') {
3146 RETURN_STATUS(bc_error("unterminated string"));
3147 }
3148 if (c == '"')
3149 break;
3150 if (c == '\n') {
3151 p->lex_line++;
3152 dbg_lex("++p->lex_line=%zd", p->lex_line);
3153 }
3154 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
3155 p->lex_inbuf++;
3156 }
3157 bc_vec_pushZeroByte(&p->lex_strnumbuf);
3158 p->lex_inbuf++;
3159
3160 G.err_line = p->lex_line;
3161 RETURN_STATUS(BC_STATUS_SUCCESS);
3162}
3163#define zbc_lex_string(...) (zbc_lex_string(__VA_ARGS__) COMMA_SUCCESS)
3164
3165static void parse_lex_by_checking_eq_sign(unsigned with_and_without)
3166{
3167 BcParse *p = &G.prs;
3168 if (*p->lex_inbuf == '=') {
3169
3170 p->lex_inbuf++;
3171 with_and_without >>= 8;
3172 }
3173 p->lex = (with_and_without & 0xff);
3174}
3175#define parse_lex_by_checking_eq_sign(with, without) \
3176 parse_lex_by_checking_eq_sign(((with)<<8)|(without))
3177
3178static BC_STATUS zbc_lex_comment(void)
3179{
3180 BcParse *p = &G.prs;
3181
3182 p->lex = XC_LEX_WHITESPACE;
3183
3184 for (;;) {
3185 char c;
3186
3187 p->lex_inbuf++;
3188 c = peek_inbuf();
3189 check_star:
3190 if (c == '*') {
3191 p->lex_inbuf++;
3192 c = *p->lex_inbuf;
3193 if (c == '/')
3194 break;
3195 goto check_star;
3196 }
3197 if (c == '\0') {
3198 RETURN_STATUS(bc_error("unterminated comment"));
3199 }
3200 if (c == '\n') {
3201 p->lex_line++;
3202 dbg_lex("++p->lex_line=%zd", p->lex_line);
3203 }
3204 }
3205 p->lex_inbuf++;
3206
3207 G.err_line = p->lex_line;
3208 RETURN_STATUS(BC_STATUS_SUCCESS);
3209}
3210#define zbc_lex_comment(...) (zbc_lex_comment(__VA_ARGS__) COMMA_SUCCESS)
3211
3212#undef zbc_lex_token
3213static BC_STATUS zbc_lex_token(void)
3214{
3215 BcParse *p = &G.prs;
3216 BcStatus s = BC_STATUS_SUCCESS;
3217 char c = eat_inbuf();
3218 char c2;
3219
3220
3221 switch (c) {
3222
3223
3224
3225
3226 case '\n':
3227 p->lex_line++;
3228 dbg_lex("++p->lex_line=%zd", p->lex_line);
3229 p->lex = XC_LEX_NLINE;
3230 break;
3231 case '\t':
3232 case '\v':
3233 case '\f':
3234 case '\r':
3235 case ' ':
3236 xc_lex_whitespace();
3237 break;
3238 case '!':
3239 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3240 if (p->lex == BC_LEX_OP_BOOL_NOT) {
3241 s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
3242 if (s) RETURN_STATUS(s);
3243 }
3244 break;
3245 case '"':
3246 s = zbc_lex_string();
3247 break;
3248 case '#':
3249 s = zbc_POSIX_does_not_allow("'#' script comments");
3250 if (s) RETURN_STATUS(s);
3251 xc_lex_lineComment();
3252 break;
3253 case '%':
3254 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MODULUS, XC_LEX_OP_MODULUS);
3255 break;
3256 case '&':
3257 c2 = *p->lex_inbuf;
3258 if (c2 == '&') {
3259 s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
3260 if (s) RETURN_STATUS(s);
3261 p->lex_inbuf++;
3262 p->lex = BC_LEX_OP_BOOL_AND;
3263 } else {
3264 p->lex = XC_LEX_INVALID;
3265 s = bc_error_bad_character('&');
3266 }
3267 break;
3268 case '(':
3269 case ')':
3270 p->lex = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3271 break;
3272 case '*':
3273 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MULTIPLY, XC_LEX_OP_MULTIPLY);
3274 break;
3275 case '+':
3276 c2 = *p->lex_inbuf;
3277 if (c2 == '+') {
3278 p->lex_inbuf++;
3279 p->lex = BC_LEX_OP_INC;
3280 } else
3281 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_PLUS, XC_LEX_OP_PLUS);
3282 break;
3283 case ',':
3284 p->lex = BC_LEX_COMMA;
3285 break;
3286 case '-':
3287 c2 = *p->lex_inbuf;
3288 if (c2 == '-') {
3289 p->lex_inbuf++;
3290 p->lex = BC_LEX_OP_DEC;
3291 } else
3292 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MINUS, XC_LEX_OP_MINUS);
3293 break;
3294 case '.':
3295 if (isdigit(*p->lex_inbuf))
3296 s = zxc_lex_number(c);
3297 else {
3298 p->lex = BC_LEX_KEY_LAST;
3299 s = zbc_POSIX_does_not_allow("'.' as 'last'");
3300 }
3301 break;
3302 case '/':
3303 c2 = *p->lex_inbuf;
3304 if (c2 == '*')
3305 s = zbc_lex_comment();
3306 else
3307 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_DIVIDE, XC_LEX_OP_DIVIDE);
3308 break;
3309 case '0':
3310 case '1':
3311 case '2':
3312 case '3':
3313 case '4':
3314 case '5':
3315 case '6':
3316 case '7':
3317 case '8':
3318 case '9':
3319 case 'A':
3320 case 'B':
3321 case 'C':
3322 case 'D':
3323 case 'E':
3324 case 'F':
3325 case 'G':
3326 case 'H':
3327 case 'I':
3328 case 'J':
3329 case 'K':
3330 case 'L':
3331 case 'M':
3332 case 'N':
3333 case 'O':
3334 case 'P':
3335 case 'Q':
3336 case 'R':
3337 case 'S':
3338 case 'T':
3339 case 'U':
3340 case 'V':
3341 case 'W':
3342 case 'X':
3343 case 'Y':
3344 case 'Z':
3345 s = zxc_lex_number(c);
3346 break;
3347 case ';':
3348 p->lex = BC_LEX_SCOLON;
3349 break;
3350 case '<':
3351 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_LE, XC_LEX_OP_REL_LT);
3352 break;
3353 case '=':
3354 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3355 break;
3356 case '>':
3357 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_GE, XC_LEX_OP_REL_GT);
3358 break;
3359 case '[':
3360 case ']':
3361 p->lex = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3362 break;
3363 case '\\':
3364 if (*p->lex_inbuf == '\n') {
3365 p->lex = XC_LEX_WHITESPACE;
3366 p->lex_inbuf++;
3367 } else
3368 s = bc_error_bad_character(c);
3369 break;
3370 case '^':
3371 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_POWER, XC_LEX_OP_POWER);
3372 break;
3373 case 'a':
3374 case 'b':
3375 case 'c':
3376 case 'd':
3377 case 'e':
3378 case 'f':
3379 case 'g':
3380 case 'h':
3381 case 'i':
3382 case 'j':
3383 case 'k':
3384 case 'l':
3385 case 'm':
3386 case 'n':
3387 case 'o':
3388 case 'p':
3389 case 'q':
3390 case 'r':
3391 case 's':
3392 case 't':
3393 case 'u':
3394 case 'v':
3395 case 'w':
3396 case 'x':
3397 case 'y':
3398 case 'z':
3399 s = zbc_lex_identifier();
3400 break;
3401 case '{':
3402 case '}':
3403 p->lex = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3404 break;
3405 case '|':
3406 c2 = *p->lex_inbuf;
3407 if (c2 == '|') {
3408 s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
3409 if (s) RETURN_STATUS(s);
3410 p->lex_inbuf++;
3411 p->lex = BC_LEX_OP_BOOL_OR;
3412 } else {
3413 p->lex = XC_LEX_INVALID;
3414 s = bc_error_bad_character(c);
3415 }
3416 break;
3417 default:
3418 p->lex = XC_LEX_INVALID;
3419 s = bc_error_bad_character(c);
3420 break;
3421 }
3422
3423 RETURN_STATUS(s);
3424}
3425#define zbc_lex_token(...) (zbc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
3426#endif
3427
3428#if ENABLE_DC
3429static BC_STATUS zdc_lex_register(void)
3430{
3431 BcParse *p = &G.prs;
3432 if (G_exreg && isspace(*p->lex_inbuf)) {
3433 xc_lex_whitespace();
3434 p->lex_inbuf++;
3435 xc_lex_name();
3436 } else {
3437 bc_vec_pop_all(&p->lex_strnumbuf);
3438 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf++);
3439 bc_vec_pushZeroByte(&p->lex_strnumbuf);
3440 p->lex = XC_LEX_NAME;
3441 }
3442
3443 RETURN_STATUS(BC_STATUS_SUCCESS);
3444}
3445#define zdc_lex_register(...) (zdc_lex_register(__VA_ARGS__) COMMA_SUCCESS)
3446
3447static BC_STATUS zdc_lex_string(void)
3448{
3449 BcParse *p = &G.prs;
3450 size_t depth;
3451
3452 p->lex = XC_LEX_STR;
3453 bc_vec_pop_all(&p->lex_strnumbuf);
3454
3455 depth = 1;
3456 for (;;) {
3457 char c = peek_inbuf();
3458 if (c == '\0') {
3459 RETURN_STATUS(bc_error("unterminated string"));
3460 }
3461 if (c == '[') depth++;
3462 if (c == ']')
3463 if (--depth == 0)
3464 break;
3465 if (c == '\n') {
3466 p->lex_line++;
3467 dbg_lex("++p->lex_line=%zd", p->lex_line);
3468 }
3469 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
3470 p->lex_inbuf++;
3471 }
3472 bc_vec_pushZeroByte(&p->lex_strnumbuf);
3473 p->lex_inbuf++;
3474
3475 G.err_line = p->lex_line;
3476 RETURN_STATUS(BC_STATUS_SUCCESS);
3477}
3478#define zdc_lex_string(...) (zdc_lex_string(__VA_ARGS__) COMMA_SUCCESS)
3479
3480#undef zdc_lex_token
3481static BC_STATUS zdc_lex_token(void)
3482{
3483 static const
3484 uint8_t
3485 dc_lex_regs[] ALIGN1 = {
3486 XC_LEX_OP_REL_EQ, XC_LEX_OP_REL_LE, XC_LEX_OP_REL_GE, XC_LEX_OP_REL_NE,
3487 XC_LEX_OP_REL_LT, XC_LEX_OP_REL_GT, DC_LEX_SCOLON, DC_LEX_COLON,
3488 DC_LEX_ELSE, DC_LEX_LOAD, DC_LEX_LOAD_POP, DC_LEX_OP_ASSIGN,
3489 DC_LEX_STORE_PUSH,
3490 };
3491
3492 BcParse *p = &G.prs;
3493 BcStatus s;
3494 char c, c2;
3495 size_t i;
3496
3497 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3498 if (p->lex_last == dc_lex_regs[i])
3499 RETURN_STATUS(zdc_lex_register());
3500 }
3501
3502 s = BC_STATUS_SUCCESS;
3503 c = eat_inbuf();
3504 if (c >= '%' && c <= '~'
3505 && (p->lex = dc_char_to_LEX[c - '%']) != XC_LEX_INVALID
3506 ) {
3507 RETURN_STATUS(s);
3508 }
3509
3510
3511 switch (c) {
3512
3513
3514
3515 case '\n':
3516
3517
3518
3519
3520
3521
3522
3523
3524 p->lex_line++;
3525 dbg_lex("++p->lex_line=%zd", p->lex_line);
3526 p->lex = XC_LEX_NLINE;
3527 break;
3528 case '\t':
3529 case '\v':
3530 case '\f':
3531 case '\r':
3532 case ' ':
3533 xc_lex_whitespace();
3534 break;
3535 case '!':
3536 c2 = *p->lex_inbuf;
3537 if (c2 == '=')
3538 p->lex = XC_LEX_OP_REL_NE;
3539 else if (c2 == '<')
3540 p->lex = XC_LEX_OP_REL_LE;
3541 else if (c2 == '>')
3542 p->lex = XC_LEX_OP_REL_GE;
3543 else
3544 RETURN_STATUS(bc_error_bad_character(c));
3545 p->lex_inbuf++;
3546 break;
3547 case '#':
3548 xc_lex_lineComment();
3549 break;
3550 case '.':
3551 if (isdigit(*p->lex_inbuf))
3552 s = zxc_lex_number(c);
3553 else
3554 s = bc_error_bad_character(c);
3555 break;
3556 case '0':
3557 case '1':
3558 case '2':
3559 case '3':
3560 case '4':
3561 case '5':
3562 case '6':
3563 case '7':
3564 case '8':
3565 case '9':
3566 case 'A':
3567 case 'B':
3568 case 'C':
3569 case 'D':
3570 case 'E':
3571 case 'F':
3572 s = zxc_lex_number(c);
3573 break;
3574 case '[':
3575 s = zdc_lex_string();
3576 break;
3577 default:
3578 p->lex = XC_LEX_INVALID;
3579 s = bc_error_bad_character(c);
3580 break;
3581 }
3582
3583 RETURN_STATUS(s);
3584}
3585#define zdc_lex_token(...) (zdc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
3586#endif
3587
3588static void xc_parse_push(unsigned i)
3589{
3590 BcVec *code = &G.prs.func->code;
3591 dbg_compile("%s:%d pushing bytecode %zd:%d", __func__, __LINE__, code->len, i);
3592 bc_vec_pushByte(code, (uint8_t)i);
3593}
3594
3595static void xc_parse_pushName(char *name)
3596{
3597#if 1
3598 BcVec *code = &G.prs.func->code;
3599 size_t pos = code->len;
3600 size_t len = strlen(name) + 1;
3601
3602 bc_vec_expand(code, pos + len);
3603 strcpy(code->v + pos, name);
3604 code->len = pos + len;
3605#else
3606
3607 do {
3608 xc_parse_push(*name);
3609 } while (*name++);
3610#endif
3611}
3612
3613
3614
3615
3616
3617#define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t))
3618
3619static void bc_vec_pushIndex(BcVec *v, size_t idx)
3620{
3621 size_t mask;
3622 unsigned amt;
3623
3624 dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx);
3625 if (idx < SMALL_INDEX_LIMIT) {
3626 bc_vec_pushByte(v, idx);
3627 return;
3628 }
3629
3630 mask = ((size_t)0xff) << (sizeof(idx) * 8 - 8);
3631 amt = sizeof(idx);
3632 for (;;) {
3633 if (idx & mask) break;
3634 mask >>= 8;
3635 amt--;
3636 }
3637
3638
3639 bc_vec_pushByte(v, (SMALL_INDEX_LIMIT - 1) + amt);
3640
3641 do {
3642 bc_vec_pushByte(v, (unsigned char)idx);
3643 idx >>= 8;
3644 } while (idx != 0);
3645}
3646
3647static void xc_parse_pushIndex(size_t idx)
3648{
3649 bc_vec_pushIndex(&G.prs.func->code, idx);
3650}
3651
3652static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx)
3653{
3654 xc_parse_push(inst);
3655 xc_parse_pushIndex(idx);
3656}
3657
3658#if ENABLE_BC
3659static void bc_parse_pushJUMP(size_t idx)
3660{
3661 xc_parse_pushInst_and_Index(BC_INST_JUMP, idx);
3662}
3663
3664static void bc_parse_pushJUMP_ZERO(size_t idx)
3665{
3666 xc_parse_pushInst_and_Index(BC_INST_JUMP_ZERO, idx);
3667}
3668
3669static BC_STATUS zbc_parse_pushSTR(void)
3670{
3671 BcParse *p = &G.prs;
3672 char *str = xstrdup(p->lex_strnumbuf.v);
3673
3674 xc_parse_pushInst_and_Index(XC_INST_STR, p->func->strs.len);
3675 bc_vec_push(&p->func->strs, &str);
3676
3677 RETURN_STATUS(zxc_lex_next());
3678}
3679#define zbc_parse_pushSTR(...) (zbc_parse_pushSTR(__VA_ARGS__) COMMA_SUCCESS)
3680#endif
3681
3682static void xc_parse_pushNUM(void)
3683{
3684 BcParse *p = &G.prs;
3685 char *num = xstrdup(p->lex_strnumbuf.v);
3686#if ENABLE_BC && ENABLE_DC
3687 size_t idx = bc_vec_push(IS_BC ? &p->func->consts : &G.prog.consts, &num);
3688#elif ENABLE_BC
3689 size_t idx = bc_vec_push(&p->func->consts, &num);
3690#else
3691 size_t idx = bc_vec_push(&G.prog.consts, &num);
3692#endif
3693 xc_parse_pushInst_and_Index(XC_INST_NUM, idx);
3694}
3695
3696static BC_STATUS zxc_parse_text_init(const char *text)
3697{
3698 G.prs.func = xc_program_func(G.prs.fidx);
3699 G.prs.lex_inbuf = text;
3700 G.prs.lex = G.prs.lex_last = XC_LEX_INVALID;
3701 RETURN_STATUS(zxc_lex_next());
3702}
3703#define zxc_parse_text_init(...) (zxc_parse_text_init(__VA_ARGS__) COMMA_SUCCESS)
3704
3705
3706
3707static void xc_program_reset(void)
3708{
3709 BcFunc *f;
3710 BcInstPtr *ip;
3711
3712 bc_vec_npop(&G.prog.exestack, G.prog.exestack.len - 1);
3713 bc_vec_pop_all(&G.prog.results);
3714
3715 f = xc_program_func_BC_PROG_MAIN();
3716 ip = bc_vec_top(&G.prog.exestack);
3717 ip->inst_idx = f->code.len;
3718}
3719
3720
3721
3722static void xc_parse_reset(void)
3723{
3724 BcParse *p = &G.prs;
3725 if (p->fidx != BC_PROG_MAIN) {
3726 bc_func_free(p->func);
3727 bc_func_init(p->func);
3728
3729 p->fidx = BC_PROG_MAIN;
3730 p->func = xc_program_func_BC_PROG_MAIN();
3731 }
3732
3733 p->lex_inbuf += strlen(p->lex_inbuf);
3734 p->lex = XC_LEX_EOF;
3735
3736 IF_BC(bc_vec_pop_all(&p->exits);)
3737 IF_BC(bc_vec_pop_all(&p->conds);)
3738 IF_BC(bc_vec_pop_all(&p->ops);)
3739
3740 xc_program_reset();
3741}
3742
3743static void xc_parse_free(void)
3744{
3745 IF_BC(bc_vec_free(&G.prs.exits);)
3746 IF_BC(bc_vec_free(&G.prs.conds);)
3747 IF_BC(bc_vec_free(&G.prs.ops);)
3748 bc_vec_free(&G.prs.lex_strnumbuf);
3749}
3750
3751static void xc_parse_create(size_t fidx)
3752{
3753 BcParse *p = &G.prs;
3754 memset(p, 0, sizeof(BcParse));
3755
3756 bc_char_vec_init(&p->lex_strnumbuf);
3757 IF_BC(bc_vec_init(&p->exits, sizeof(size_t), NULL);)
3758 IF_BC(bc_vec_init(&p->conds, sizeof(size_t), NULL);)
3759 IF_BC(bc_vec_init(&p->ops, sizeof(BcLexType), NULL);)
3760
3761 p->fidx = fidx;
3762 p->func = xc_program_func(fidx);
3763}
3764
3765static void xc_program_add_fn(void)
3766{
3767
3768 BcFunc f;
3769 bc_func_init(&f);
3770
3771 bc_vec_push(&G.prog.fns, &f);
3772
3773}
3774
3775#if ENABLE_BC
3776
3777
3778static size_t bc_program_addFunc(char *name)
3779{
3780 size_t idx;
3781 BcId entry, *entry_ptr;
3782 int inserted;
3783
3784 entry.name = name;
3785 entry.idx = G.prog.fns.len;
3786
3787 inserted = bc_map_insert(&G.prog.fn_map, &entry, &idx);
3788 if (!inserted) free(name);
3789
3790 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3791 idx = entry_ptr->idx;
3792
3793 if (!inserted) {
3794
3795
3796 BcFunc *func = xc_program_func(entry_ptr->idx);
3797 bc_func_free(func);
3798 bc_func_init(func);
3799 } else {
3800 xc_program_add_fn();
3801 }
3802
3803 return idx;
3804}
3805
3806#define BC_PARSE_TOP_OP(p) (*(BcLexType*)bc_vec_top(&(p)->ops))
3807
3808
3809
3810#define BC_TOKEN_2_INST(t) ((char) ((t) - XC_LEX_OP_POWER + XC_INST_POWER))
3811
3812static BC_STATUS zbc_parse_expr(uint8_t flags);
3813#define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
3814
3815static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed);
3816#define zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__) COMMA_SUCCESS)
3817
3818static BC_STATUS zbc_parse_stmt(void)
3819{
3820 RETURN_STATUS(zbc_parse_stmt_possibly_auto(false));
3821}
3822#define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__) COMMA_SUCCESS)
3823
3824static BC_STATUS zbc_parse_stmt_allow_NLINE_before(const char *after_X)
3825{
3826 BcParse *p = &G.prs;
3827
3828
3829 BcStatus s = zbc_lex_next_and_skip_NLINE();
3830 if (s) RETURN_STATUS(s);
3831 if (p->lex == XC_LEX_NLINE)
3832 RETURN_STATUS(bc_error_fmt("no statement after '%s'", after_X));
3833
3834 RETURN_STATUS(zbc_parse_stmt());
3835}
3836#define zbc_parse_stmt_allow_NLINE_before(...) (zbc_parse_stmt_allow_NLINE_before(__VA_ARGS__) COMMA_SUCCESS)
3837
3838static void bc_parse_operator(BcLexType type, size_t start, size_t *nexprs)
3839{
3840 BcParse *p = &G.prs;
3841 char l, r = bc_operation_PREC(type - XC_LEX_1st_op);
3842 bool left = bc_operation_LEFT(type - XC_LEX_1st_op);
3843
3844 while (p->ops.len > start) {
3845 BcLexType t = BC_PARSE_TOP_OP(p);
3846 if (t == BC_LEX_LPAREN) break;
3847
3848 l = bc_operation_PREC(t - XC_LEX_1st_op);
3849 if (l >= r && (l != r || !left)) break;
3850
3851 xc_parse_push(BC_TOKEN_2_INST(t));
3852 bc_vec_pop(&p->ops);
3853 *nexprs -= (t != BC_LEX_OP_BOOL_NOT && t != XC_LEX_NEG);
3854 }
3855
3856 bc_vec_push(&p->ops, &type);
3857}
3858
3859static BC_STATUS zbc_parse_rightParen(size_t ops_bgn, size_t *nexs)
3860{
3861 BcParse *p = &G.prs;
3862 BcLexType top;
3863
3864 if (p->ops.len <= ops_bgn)
3865 RETURN_STATUS(bc_error_bad_expression());
3866 top = BC_PARSE_TOP_OP(p);
3867
3868 while (top != BC_LEX_LPAREN) {
3869 xc_parse_push(BC_TOKEN_2_INST(top));
3870
3871 bc_vec_pop(&p->ops);
3872 *nexs -= (top != BC_LEX_OP_BOOL_NOT && top != XC_LEX_NEG);
3873
3874 if (p->ops.len <= ops_bgn)
3875 RETURN_STATUS(bc_error_bad_expression());
3876 top = BC_PARSE_TOP_OP(p);
3877 }
3878
3879 bc_vec_pop(&p->ops);
3880
3881 RETURN_STATUS(BC_STATUS_SUCCESS);
3882}
3883#define zbc_parse_rightParen(...) (zbc_parse_rightParen(__VA_ARGS__) COMMA_SUCCESS)
3884
3885static BC_STATUS zbc_parse_params(uint8_t flags)
3886{
3887 BcParse *p = &G.prs;
3888 BcStatus s;
3889 size_t nparams;
3890
3891 dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
3892 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3893
3894 s = zxc_lex_next();
3895 if (s) RETURN_STATUS(s);
3896
3897 nparams = 0;
3898 if (p->lex != BC_LEX_RPAREN) {
3899 for (;;) {
3900 s = zbc_parse_expr(flags);
3901 if (s) RETURN_STATUS(s);
3902 nparams++;
3903 if (p->lex != BC_LEX_COMMA) {
3904 if (p->lex == BC_LEX_RPAREN)
3905 break;
3906 RETURN_STATUS(bc_error_bad_token());
3907 }
3908 s = zxc_lex_next();
3909 if (s) RETURN_STATUS(s);
3910 }
3911 }
3912
3913 xc_parse_pushInst_and_Index(BC_INST_CALL, nparams);
3914
3915 RETURN_STATUS(BC_STATUS_SUCCESS);
3916}
3917#define zbc_parse_params(...) (zbc_parse_params(__VA_ARGS__) COMMA_SUCCESS)
3918
3919
3920static BC_STATUS zbc_parse_call(char *name, uint8_t flags)
3921{
3922 BcParse *p = &G.prs;
3923 BcStatus s;
3924 BcId entry, *entry_ptr;
3925 size_t idx;
3926
3927 entry.name = name;
3928
3929 s = zbc_parse_params(flags);
3930 if (s) goto err;
3931
3932 if (p->lex != BC_LEX_RPAREN) {
3933 s = bc_error_bad_token();
3934 goto err;
3935 }
3936
3937 idx = bc_map_find_exact(&G.prog.fn_map, &entry);
3938
3939 if (idx == BC_VEC_INVALID_IDX) {
3940
3941 bc_program_addFunc(name);
3942 idx = bc_map_find_exact(&G.prog.fn_map, &entry);
3943 } else
3944 free(name);
3945
3946 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3947 xc_parse_pushIndex(entry_ptr->idx);
3948
3949 RETURN_STATUS(zxc_lex_next());
3950 err:
3951 free(name);
3952 RETURN_STATUS(s);
3953}
3954#define zbc_parse_call(...) (zbc_parse_call(__VA_ARGS__) COMMA_SUCCESS)
3955
3956static BC_STATUS zbc_parse_name(BcInst *type, uint8_t flags)
3957{
3958 BcParse *p = &G.prs;
3959 BcStatus s;
3960 char *name;
3961
3962 name = xstrdup(p->lex_strnumbuf.v);
3963 s = zxc_lex_next();
3964 if (s) goto err;
3965
3966 if (p->lex == BC_LEX_LBRACKET) {
3967 s = zxc_lex_next();
3968 if (s) goto err;
3969
3970 if (p->lex == BC_LEX_RBRACKET) {
3971 if (!(flags & BC_PARSE_ARRAY)) {
3972 s = bc_error_bad_expression();
3973 goto err;
3974 }
3975 *type = XC_INST_ARRAY;
3976 } else {
3977 *type = XC_INST_ARRAY_ELEM;
3978 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3979 s = zbc_parse_expr(flags);
3980 if (s) goto err;
3981 }
3982 s = zxc_lex_next();
3983 if (s) goto err;
3984 xc_parse_push(*type);
3985 xc_parse_pushName(name);
3986 free(name);
3987 } else if (p->lex == BC_LEX_LPAREN) {
3988 if (flags & BC_PARSE_NOCALL) {
3989 s = bc_error_bad_token();
3990 goto err;
3991 }
3992 *type = BC_INST_CALL;
3993 s = zbc_parse_call(name, flags);
3994 } else {
3995 *type = XC_INST_VAR;
3996 xc_parse_push(XC_INST_VAR);
3997 xc_parse_pushName(name);
3998 free(name);
3999 }
4000
4001 RETURN_STATUS(s);
4002 err:
4003 free(name);
4004 RETURN_STATUS(s);
4005}
4006#define zbc_parse_name(...) (zbc_parse_name(__VA_ARGS__) COMMA_SUCCESS)
4007
4008static BC_STATUS zbc_parse_read(void)
4009{
4010 BcParse *p = &G.prs;
4011 BcStatus s;
4012
4013 s = zxc_lex_next();
4014 if (s) RETURN_STATUS(s);
4015 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
4016
4017 s = zxc_lex_next();
4018 if (s) RETURN_STATUS(s);
4019 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4020
4021 xc_parse_push(XC_INST_READ);
4022
4023 RETURN_STATUS(s);
4024}
4025#define zbc_parse_read(...) (zbc_parse_read(__VA_ARGS__) COMMA_SUCCESS)
4026
4027static BC_STATUS zbc_parse_builtin(BcLexType type, uint8_t flags, BcInst *prev)
4028{
4029 BcParse *p = &G.prs;
4030 BcStatus s;
4031
4032 s = zxc_lex_next();
4033 if (s) RETURN_STATUS(s);
4034 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
4035
4036 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
4037
4038 s = zxc_lex_next();
4039 if (s) RETURN_STATUS(s);
4040
4041 s = zbc_parse_expr(flags);
4042 if (s) RETURN_STATUS(s);
4043
4044 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4045
4046 *prev = (type == BC_LEX_KEY_LENGTH) ? XC_INST_LENGTH : XC_INST_SQRT;
4047 xc_parse_push(*prev);
4048
4049 RETURN_STATUS(s);
4050}
4051#define zbc_parse_builtin(...) (zbc_parse_builtin(__VA_ARGS__) COMMA_SUCCESS)
4052
4053static BC_STATUS zbc_parse_scale(BcInst *type, uint8_t flags)
4054{
4055 BcParse *p = &G.prs;
4056 BcStatus s;
4057
4058 s = zxc_lex_next();
4059 if (s) RETURN_STATUS(s);
4060
4061 if (p->lex != BC_LEX_LPAREN) {
4062 *type = XC_INST_SCALE;
4063 xc_parse_push(XC_INST_SCALE);
4064 RETURN_STATUS(BC_STATUS_SUCCESS);
4065 }
4066
4067 *type = XC_INST_SCALE_FUNC;
4068 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
4069
4070 s = zxc_lex_next();
4071 if (s) RETURN_STATUS(s);
4072
4073 s = zbc_parse_expr(flags);
4074 if (s) RETURN_STATUS(s);
4075 if (p->lex != BC_LEX_RPAREN)
4076 RETURN_STATUS(bc_error_bad_token());
4077 xc_parse_push(XC_INST_SCALE_FUNC);
4078
4079 RETURN_STATUS(zxc_lex_next());
4080}
4081#define zbc_parse_scale(...) (zbc_parse_scale(__VA_ARGS__) COMMA_SUCCESS)
4082
4083static BC_STATUS zbc_parse_incdec(BcInst *prev, size_t *nexs, uint8_t flags)
4084{
4085 BcParse *p = &G.prs;
4086 BcStatus s;
4087 BcLexType type;
4088 char inst;
4089 BcInst etype = *prev;
4090
4091 if (etype == XC_INST_VAR || etype == XC_INST_ARRAY_ELEM
4092 || etype == XC_INST_SCALE || etype == BC_INST_LAST
4093 || etype == XC_INST_IBASE || etype == XC_INST_OBASE
4094 ) {
4095 *prev = inst = BC_INST_INC_POST + (p->lex != BC_LEX_OP_INC);
4096 xc_parse_push(inst);
4097 s = zxc_lex_next();
4098 } else {
4099 *prev = inst = BC_INST_INC_PRE + (p->lex != BC_LEX_OP_INC);
4100
4101 s = zxc_lex_next();
4102 if (s) RETURN_STATUS(s);
4103 type = p->lex;
4104
4105
4106
4107 *nexs = *nexs + 1;
4108
4109 switch (type) {
4110 case XC_LEX_NAME:
4111 s = zbc_parse_name(prev, flags | BC_PARSE_NOCALL);
4112 break;
4113 case BC_LEX_KEY_IBASE:
4114 case BC_LEX_KEY_LAST:
4115 case BC_LEX_KEY_OBASE:
4116 xc_parse_push(type - BC_LEX_KEY_IBASE + XC_INST_IBASE);
4117 s = zxc_lex_next();
4118 break;
4119 case BC_LEX_KEY_SCALE:
4120 s = zxc_lex_next();
4121 if (s) RETURN_STATUS(s);
4122 if (p->lex == BC_LEX_LPAREN)
4123 s = bc_error_bad_token();
4124 else
4125 xc_parse_push(XC_INST_SCALE);
4126 break;
4127 default:
4128 s = bc_error_bad_token();
4129 break;
4130 }
4131
4132 if (!s) xc_parse_push(inst);
4133 }
4134
4135 RETURN_STATUS(s);
4136}
4137#define zbc_parse_incdec(...) (zbc_parse_incdec(__VA_ARGS__) COMMA_SUCCESS)
4138
4139static int bc_parse_inst_isLeaf(BcInst p)
4140{
4141 return (p >= XC_INST_NUM && p <= XC_INST_SQRT)
4142 || p == BC_INST_INC_POST
4143 || p == BC_INST_DEC_POST
4144 ;
4145}
4146#define BC_PARSE_LEAF(prev, bin_last, rparen) \
4147 (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))
4148
4149static BC_STATUS zbc_parse_minus(BcInst *prev, size_t ops_bgn,
4150 bool rparen, bool bin_last, size_t *nexprs)
4151{
4152 BcParse *p = &G.prs;
4153 BcStatus s;
4154 BcLexType type;
4155
4156 s = zxc_lex_next();
4157 if (s) RETURN_STATUS(s);
4158
4159 type = BC_PARSE_LEAF(*prev, bin_last, rparen) ? XC_LEX_OP_MINUS : XC_LEX_NEG;
4160 *prev = BC_TOKEN_2_INST(type);
4161
4162
4163
4164 if (type != XC_LEX_OP_MINUS)
4165 bc_vec_push(&p->ops, &type);
4166 else
4167 bc_parse_operator(type, ops_bgn, nexprs);
4168
4169 RETURN_STATUS(s);
4170}
4171#define zbc_parse_minus(...) (zbc_parse_minus(__VA_ARGS__) COMMA_SUCCESS)
4172
4173static BC_STATUS zbc_parse_print(void)
4174{
4175 BcParse *p = &G.prs;
4176 BcStatus s;
4177 BcLexType type;
4178
4179 for (;;) {
4180 s = zxc_lex_next();
4181 if (s) RETURN_STATUS(s);
4182 type = p->lex;
4183 if (type == XC_LEX_STR) {
4184 s = zbc_parse_pushSTR();
4185 } else {
4186 s = zbc_parse_expr(0);
4187 }
4188 if (s) RETURN_STATUS(s);
4189 xc_parse_push(XC_INST_PRINT_POP);
4190 if (p->lex != BC_LEX_COMMA)
4191 break;
4192 }
4193
4194 RETURN_STATUS(s);
4195}
4196#define zbc_parse_print(...) (zbc_parse_print(__VA_ARGS__) COMMA_SUCCESS)
4197
4198static BC_STATUS zbc_parse_return(void)
4199{
4200 BcParse *p = &G.prs;
4201 BcStatus s;
4202 BcLexType t;
4203
4204 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
4205 s = zxc_lex_next();
4206 if (s) RETURN_STATUS(s);
4207
4208 t = p->lex;
4209 if (t == XC_LEX_NLINE || t == BC_LEX_SCOLON || t == BC_LEX_RBRACE)
4210 xc_parse_push(BC_INST_RET0);
4211 else {
4212
4213 s = zbc_parse_expr(0);
4214 if (s) RETURN_STATUS(s);
4215
4216 if (t != BC_LEX_LPAREN
4217 || p->lex_last != BC_LEX_RPAREN
4218 ) {
4219 s = zbc_POSIX_requires("parentheses around return expressions");
4220 if (s) RETURN_STATUS(s);
4221 }
4222
4223 xc_parse_push(XC_INST_RET);
4224 }
4225
4226 dbg_lex_done("%s:%d done", __func__, __LINE__);
4227 RETURN_STATUS(s);
4228}
4229#define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__) COMMA_SUCCESS)
4230
4231static void rewrite_label_to_current(size_t idx)
4232{
4233 BcParse *p = &G.prs;
4234 size_t *label = bc_vec_item(&p->func->labels, idx);
4235 *label = p->func->code.len;
4236}
4237
4238static BC_STATUS zbc_parse_if(void)
4239{
4240 BcParse *p = &G.prs;
4241 BcStatus s;
4242 size_t ip_idx;
4243
4244 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
4245 s = zxc_lex_next();
4246 if (s) RETURN_STATUS(s);
4247 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
4248
4249 s = zxc_lex_next();
4250 if (s) RETURN_STATUS(s);
4251 s = zbc_parse_expr(BC_PARSE_REL);
4252 if (s) RETURN_STATUS(s);
4253 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4254
4255
4256
4257
4258 ip_idx = bc_vec_push(&p->func->labels, &ip_idx);
4259 bc_parse_pushJUMP_ZERO(ip_idx);
4260
4261 s = zbc_parse_stmt_allow_NLINE_before(STRING_if);
4262 if (s) RETURN_STATUS(s);
4263
4264 dbg_lex("%s:%d in if after stmt: p->lex:%d", __func__, __LINE__, p->lex);
4265 if (p->lex == BC_LEX_KEY_ELSE) {
4266 size_t ip2_idx;
4267
4268
4269 ip2_idx = bc_vec_push(&p->func->labels, &ip2_idx);
4270 dbg_lex("%s:%d after if() then_stmt: BC_INST_JUMP to %zd", __func__, __LINE__, ip2_idx);
4271 bc_parse_pushJUMP(ip2_idx);
4272
4273 dbg_lex("%s:%d rewriting 'if_zero' label to jump to 'else'-> %zd", __func__, __LINE__, p->func->code.len);
4274 rewrite_label_to_current(ip_idx);
4275
4276 ip_idx = ip2_idx;
4277
4278 s = zbc_parse_stmt_allow_NLINE_before(STRING_else);
4279 if (s) RETURN_STATUS(s);
4280 }
4281
4282 dbg_lex("%s:%d rewriting label to jump after 'if' body-> %zd", __func__, __LINE__, p->func->code.len);
4283 rewrite_label_to_current(ip_idx);
4284
4285 dbg_lex_done("%s:%d done", __func__, __LINE__);
4286 RETURN_STATUS(s);
4287}
4288#define zbc_parse_if(...) (zbc_parse_if(__VA_ARGS__) COMMA_SUCCESS)
4289
4290static BC_STATUS zbc_parse_while(void)
4291{
4292 BcParse *p = &G.prs;
4293 BcStatus s;
4294 size_t cond_idx;
4295 size_t ip_idx;
4296
4297 s = zxc_lex_next();
4298 if (s) RETURN_STATUS(s);
4299 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
4300 s = zxc_lex_next();
4301 if (s) RETURN_STATUS(s);
4302
4303 cond_idx = bc_vec_push(&p->func->labels, &p->func->code.len);
4304 ip_idx = cond_idx + 1;
4305 bc_vec_push(&p->conds, &cond_idx);
4306
4307 bc_vec_push(&p->exits, &ip_idx);
4308 bc_vec_push(&p->func->labels, &ip_idx);
4309
4310 s = zbc_parse_expr(BC_PARSE_REL);
4311 if (s) RETURN_STATUS(s);
4312 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4313
4314 bc_parse_pushJUMP_ZERO(ip_idx);
4315
4316 s = zbc_parse_stmt_allow_NLINE_before(STRING_while);
4317 if (s) RETURN_STATUS(s);
4318
4319 dbg_lex("%s:%d BC_INST_JUMP to %zd", __func__, __LINE__, cond_idx);
4320 bc_parse_pushJUMP(cond_idx);
4321
4322 dbg_lex("%s:%d rewriting label-> %zd", __func__, __LINE__, p->func->code.len);
4323 rewrite_label_to_current(ip_idx);
4324
4325 bc_vec_pop(&p->exits);
4326 bc_vec_pop(&p->conds);
4327
4328 RETURN_STATUS(s);
4329}
4330#define zbc_parse_while(...) (zbc_parse_while(__VA_ARGS__) COMMA_SUCCESS)
4331
4332static BC_STATUS zbc_parse_for(void)
4333{
4334 BcParse *p = &G.prs;
4335 BcStatus s;
4336 size_t cond_idx, exit_idx, body_idx, update_idx;
4337
4338 dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
4339 s = zxc_lex_next();
4340 if (s) RETURN_STATUS(s);
4341 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
4342 s = zxc_lex_next();
4343 if (s) RETURN_STATUS(s);
4344
4345 if (p->lex != BC_LEX_SCOLON) {
4346 s = zbc_parse_expr(0);
4347 xc_parse_push(XC_INST_POP);
4348 if (s) RETURN_STATUS(s);
4349 } else {
4350 s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4351 if (s) RETURN_STATUS(s);
4352 }
4353
4354 if (p->lex != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
4355 s = zxc_lex_next();
4356 if (s) RETURN_STATUS(s);
4357
4358 cond_idx = bc_vec_push(&p->func->labels, &p->func->code.len);
4359 update_idx = cond_idx + 1;
4360 body_idx = update_idx + 1;
4361 exit_idx = body_idx + 1;
4362
4363 if (p->lex != BC_LEX_SCOLON)
4364 s = zbc_parse_expr(BC_PARSE_REL);
4365 else {
4366
4367
4368
4369 bc_vec_string(&p->lex_strnumbuf, 1, "1");
4370 xc_parse_pushNUM();
4371 s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
4372 }
4373 if (s) RETURN_STATUS(s);
4374
4375 if (p->lex != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
4376
4377 s = zxc_lex_next();
4378 if (s) RETURN_STATUS(s);
4379
4380 bc_parse_pushJUMP_ZERO(exit_idx);
4381 bc_parse_pushJUMP(body_idx);
4382
4383 bc_vec_push(&p->conds, &update_idx);
4384 bc_vec_push(&p->func->labels, &p->func->code.len);
4385
4386 if (p->lex != BC_LEX_RPAREN) {
4387 s = zbc_parse_expr(0);
4388 if (s) RETURN_STATUS(s);
4389 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4390 xc_parse_push(XC_INST_POP);
4391 } else {
4392 s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4393 if (s) RETURN_STATUS(s);
4394 }
4395
4396 bc_parse_pushJUMP(cond_idx);
4397 bc_vec_push(&p->func->labels, &p->func->code.len);
4398
4399 bc_vec_push(&p->exits, &exit_idx);
4400 bc_vec_push(&p->func->labels, &exit_idx);
4401
4402 s = zbc_parse_stmt_allow_NLINE_before(STRING_for);
4403 if (s) RETURN_STATUS(s);
4404
4405 dbg_lex("%s:%d BC_INST_JUMP to %zd", __func__, __LINE__, update_idx);
4406 bc_parse_pushJUMP(update_idx);
4407
4408 dbg_lex("%s:%d rewriting label-> %zd", __func__, __LINE__, p->func->code.len);
4409 rewrite_label_to_current(exit_idx);
4410
4411 bc_vec_pop(&p->exits);
4412 bc_vec_pop(&p->conds);
4413
4414 RETURN_STATUS(BC_STATUS_SUCCESS);
4415}
4416#define zbc_parse_for(...) (zbc_parse_for(__VA_ARGS__) COMMA_SUCCESS)
4417
4418static BC_STATUS zbc_parse_break_or_continue(BcLexType type)
4419{
4420 BcParse *p = &G.prs;
4421 size_t i;
4422
4423 if (type == BC_LEX_KEY_BREAK) {
4424 if (p->exits.len == 0)
4425 RETURN_STATUS(bc_error_bad_token());
4426 i = *(size_t*)bc_vec_top(&p->exits);
4427 } else {
4428 i = *(size_t*)bc_vec_top(&p->conds);
4429 }
4430 bc_parse_pushJUMP(i);
4431
4432 RETURN_STATUS(zxc_lex_next());
4433}
4434#define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS)
4435
4436static BC_STATUS zbc_func_insert(BcFunc *f, char *name, BcType type)
4437{
4438 BcId *autoid;
4439 BcId a;
4440 size_t i;
4441
4442 autoid = (void*)f->autos.v;
4443 for (i = 0; i < f->autos.len; i++, autoid++) {
4444 if (strcmp(name, autoid->name) == 0
4445 && type == (BcType) autoid->idx
4446 ) {
4447 RETURN_STATUS(bc_error("duplicate function parameter or auto name"));
4448 }
4449 }
4450
4451 a.idx = type;
4452 a.name = name;
4453
4454 bc_vec_push(&f->autos, &a);
4455
4456 RETURN_STATUS(BC_STATUS_SUCCESS);
4457}
4458#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS)
4459
4460static BC_STATUS zbc_parse_funcdef(void)
4461{
4462 BcParse *p = &G.prs;
4463 BcStatus s;
4464 bool comma, voidfunc;
4465 char *name;
4466
4467 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
4468 s = zxc_lex_next();
4469 if (s) RETURN_STATUS(s);
4470 if (p->lex != XC_LEX_NAME)
4471 RETURN_STATUS(bc_error_bad_function_definition());
4472
4473
4474
4475
4476
4477
4478
4479 voidfunc = (strcmp(p->lex_strnumbuf.v, "void") == 0);
4480
4481 s = zxc_lex_next();
4482 if (s) RETURN_STATUS(s);
4483
4484 voidfunc = (voidfunc && p->lex == XC_LEX_NAME);
4485 if (voidfunc) {
4486 s = zxc_lex_next();
4487 if (s) RETURN_STATUS(s);
4488 }
4489
4490 if (p->lex != BC_LEX_LPAREN)
4491 RETURN_STATUS(bc_error_bad_function_definition());
4492
4493 p->fidx = bc_program_addFunc(xstrdup(p->lex_strnumbuf.v));
4494 p->func = xc_program_func(p->fidx);
4495 p->func->voidfunc = voidfunc;
4496
4497 s = zxc_lex_next();
4498 if (s) RETURN_STATUS(s);
4499
4500 comma = false;
4501 while (p->lex != BC_LEX_RPAREN) {
4502 BcType t = BC_TYPE_VAR;
4503
4504 if (p->lex == XC_LEX_OP_MULTIPLY) {
4505 t = BC_TYPE_REF;
4506 s = zxc_lex_next();
4507 if (s) RETURN_STATUS(s);
4508 s = zbc_POSIX_does_not_allow("references");
4509 if (s) RETURN_STATUS(s);
4510 }
4511
4512 if (p->lex != XC_LEX_NAME)
4513 RETURN_STATUS(bc_error_bad_function_definition());
4514
4515 ++p->func->nparams;
4516
4517 name = xstrdup(p->lex_strnumbuf.v);
4518 s = zxc_lex_next();
4519 if (s) goto err;
4520
4521 if (p->lex == BC_LEX_LBRACKET) {
4522 if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
4523 s = zxc_lex_next();
4524 if (s) goto err;
4525
4526 if (p->lex != BC_LEX_RBRACKET) {
4527 s = bc_error_bad_function_definition();
4528 goto err;
4529 }
4530
4531 s = zxc_lex_next();
4532 if (s) goto err;
4533 }
4534 else if (t == BC_TYPE_REF) {
4535 s = bc_error_at("vars can't be references");
4536 goto err;
4537 }
4538
4539 comma = p->lex == BC_LEX_COMMA;
4540 if (comma) {
4541 s = zxc_lex_next();
4542 if (s) goto err;
4543 }
4544
4545 s = zbc_func_insert(p->func, name, t);
4546 if (s) goto err;
4547 }
4548
4549 if (comma) RETURN_STATUS(bc_error_bad_function_definition());
4550
4551 s = zxc_lex_next();
4552 if (s) RETURN_STATUS(s);
4553
4554 if (p->lex != BC_LEX_LBRACE) {
4555 s = zbc_POSIX_requires("the left brace be on the same line as the function header");
4556 if (s) RETURN_STATUS(s);
4557 }
4558
4559
4560 s = zbc_lex_skip_if_at_NLINE();
4561 if (s) RETURN_STATUS(s);
4562
4563 if (p->lex != BC_LEX_LBRACE)
4564 RETURN_STATUS(bc_error("function { body } expected"));
4565
4566 p->in_funcdef++;
4567 s = zbc_parse_stmt_possibly_auto(true);
4568 p->in_funcdef--;
4569 if (s) RETURN_STATUS(s);
4570
4571 xc_parse_push(BC_INST_RET0);
4572
4573
4574 p->fidx = BC_PROG_MAIN;
4575 p->func = xc_program_func_BC_PROG_MAIN();
4576
4577 dbg_lex_done("%s:%d done", __func__, __LINE__);
4578 RETURN_STATUS(s);
4579 err:
4580 dbg_lex_done("%s:%d done (error)", __func__, __LINE__);
4581 free(name);
4582 RETURN_STATUS(s);
4583}
4584#define zbc_parse_funcdef(...) (zbc_parse_funcdef(__VA_ARGS__) COMMA_SUCCESS)
4585
4586static BC_STATUS zbc_parse_auto(void)
4587{
4588 BcParse *p = &G.prs;
4589 BcStatus s;
4590 char *name;
4591
4592 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
4593 s = zxc_lex_next();
4594 if (s) RETURN_STATUS(s);
4595
4596 for (;;) {
4597 BcType t;
4598
4599 if (p->lex != XC_LEX_NAME)
4600 RETURN_STATUS(bc_error_at("bad 'auto' syntax"));
4601
4602 name = xstrdup(p->lex_strnumbuf.v);
4603 s = zxc_lex_next();
4604 if (s) goto err;
4605
4606 t = BC_TYPE_VAR;
4607 if (p->lex == BC_LEX_LBRACKET) {
4608 t = BC_TYPE_ARRAY;
4609 s = zxc_lex_next();
4610 if (s) goto err;
4611
4612 if (p->lex != BC_LEX_RBRACKET) {
4613 s = bc_error_at("bad 'auto' syntax");
4614 goto err;
4615 }
4616 s = zxc_lex_next();
4617 if (s) goto err;
4618 }
4619
4620 s = zbc_func_insert(p->func, name, t);
4621 if (s) goto err;
4622
4623 if (p->lex == XC_LEX_NLINE
4624 || p->lex == BC_LEX_SCOLON
4625
4626 ) {
4627 break;
4628 }
4629 if (p->lex != BC_LEX_COMMA)
4630 RETURN_STATUS(bc_error_at("bad 'auto' syntax"));
4631 s = zxc_lex_next();
4632 if (s) RETURN_STATUS(s);
4633 }
4634
4635 dbg_lex_done("%s:%d done", __func__, __LINE__);
4636 RETURN_STATUS(BC_STATUS_SUCCESS);
4637 err:
4638 free(name);
4639 dbg_lex_done("%s:%d done (ERROR)", __func__, __LINE__);
4640 RETURN_STATUS(s);
4641}
4642#define zbc_parse_auto(...) (zbc_parse_auto(__VA_ARGS__) COMMA_SUCCESS)
4643
4644#undef zbc_parse_stmt_possibly_auto
4645static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed)
4646{
4647 BcParse *p = &G.prs;
4648 BcStatus s = BC_STATUS_SUCCESS;
4649
4650 dbg_lex_enter("%s:%d entered, p->lex:%d", __func__, __LINE__, p->lex);
4651
4652 if (p->lex == XC_LEX_NLINE) {
4653 dbg_lex_done("%s:%d done (seen XC_LEX_NLINE)", __func__, __LINE__);
4654 RETURN_STATUS(s);
4655 }
4656 if (p->lex == BC_LEX_SCOLON) {
4657 dbg_lex_done("%s:%d done (seen BC_LEX_SCOLON)", __func__, __LINE__);
4658 RETURN_STATUS(s);
4659 }
4660
4661 if (p->lex == BC_LEX_LBRACE) {
4662 dbg_lex("%s:%d BC_LEX_LBRACE: (auto_allowed:%d)", __func__, __LINE__, auto_allowed);
4663 do {
4664 s = zxc_lex_next();
4665 if (s) RETURN_STATUS(s);
4666 } while (p->lex == XC_LEX_NLINE);
4667 if (auto_allowed && p->lex == BC_LEX_KEY_AUTO) {
4668 dbg_lex("%s:%d calling zbc_parse_auto()", __func__, __LINE__);
4669 s = zbc_parse_auto();
4670 if (s) RETURN_STATUS(s);
4671 }
4672 while (p->lex != BC_LEX_RBRACE) {
4673 dbg_lex("%s:%d block parsing loop", __func__, __LINE__);
4674 s = zbc_parse_stmt();
4675 if (s) RETURN_STATUS(s);
4676
4677
4678 if (p->lex == BC_LEX_RBRACE)
4679 break;
4680 if (p->lex != BC_LEX_SCOLON
4681 && p->lex != XC_LEX_NLINE
4682 ) {
4683 RETURN_STATUS(bc_error_at("bad statement terminator"));
4684 }
4685 s = zxc_lex_next();
4686 if (s) RETURN_STATUS(s);
4687 }
4688 s = zxc_lex_next();
4689 dbg_lex_done("%s:%d done (seen BC_LEX_RBRACE)", __func__, __LINE__);
4690 RETURN_STATUS(s);
4691 }
4692
4693 dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
4694 switch (p->lex) {
4695 case XC_LEX_OP_MINUS:
4696 case BC_LEX_OP_INC:
4697 case BC_LEX_OP_DEC:
4698 case BC_LEX_OP_BOOL_NOT:
4699 case BC_LEX_LPAREN:
4700 case XC_LEX_NAME:
4701 case XC_LEX_NUMBER:
4702 case BC_LEX_KEY_IBASE:
4703 case BC_LEX_KEY_LAST:
4704 case BC_LEX_KEY_LENGTH:
4705 case BC_LEX_KEY_OBASE:
4706 case BC_LEX_KEY_READ:
4707 case BC_LEX_KEY_SCALE:
4708 case BC_LEX_KEY_SQRT:
4709 s = zbc_parse_expr(BC_PARSE_PRINT);
4710 break;
4711 case XC_LEX_STR:
4712 s = zbc_parse_pushSTR();
4713 xc_parse_push(XC_INST_PRINT_STR);
4714 break;
4715 case BC_LEX_KEY_BREAK:
4716 case BC_LEX_KEY_CONTINUE:
4717 s = zbc_parse_break_or_continue(p->lex);
4718 break;
4719 case BC_LEX_KEY_FOR:
4720 s = zbc_parse_for();
4721 break;
4722 case BC_LEX_KEY_HALT:
4723 xc_parse_push(BC_INST_HALT);
4724 s = zxc_lex_next();
4725 break;
4726 case BC_LEX_KEY_IF:
4727 s = zbc_parse_if();
4728 break;
4729 case BC_LEX_KEY_LIMITS:
4730
4731
4732 printf(
4733 "BC_BASE_MAX = "BC_MAX_OBASE_STR "\n"
4734 "BC_DIM_MAX = "BC_MAX_DIM_STR "\n"
4735 "BC_SCALE_MAX = "BC_MAX_SCALE_STR "\n"
4736 "BC_STRING_MAX = "BC_MAX_STRING_STR"\n"
4737
4738 "MAX Exponent = "BC_MAX_EXP_STR "\n"
4739 "Number of vars = "BC_MAX_VARS_STR "\n"
4740 );
4741 s = zxc_lex_next();
4742 break;
4743 case BC_LEX_KEY_PRINT:
4744 s = zbc_parse_print();
4745 break;
4746 case BC_LEX_KEY_QUIT:
4747
4748
4749
4750 QUIT_OR_RETURN_TO_MAIN;
4751 case BC_LEX_KEY_RETURN:
4752 if (!p->in_funcdef)
4753 RETURN_STATUS(bc_error("'return' not in a function"));
4754 s = zbc_parse_return();
4755 break;
4756 case BC_LEX_KEY_WHILE:
4757 s = zbc_parse_while();
4758 break;
4759 default:
4760 s = bc_error_bad_token();
4761 break;
4762 }
4763
4764 dbg_lex_done("%s:%d done", __func__, __LINE__);
4765 RETURN_STATUS(s);
4766}
4767#define zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__) COMMA_SUCCESS)
4768
4769static BC_STATUS zbc_parse_stmt_or_funcdef(void)
4770{
4771 BcParse *p = &G.prs;
4772 BcStatus s;
4773
4774 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
4775
4776
4777
4778
4779 if (p->lex == BC_LEX_KEY_DEFINE) {
4780 dbg_lex("%s:%d p->lex:BC_LEX_KEY_DEFINE", __func__, __LINE__);
4781 s = zbc_parse_funcdef();
4782 } else {
4783 dbg_lex("%s:%d p->lex:%d (not BC_LEX_KEY_DEFINE)", __func__, __LINE__, p->lex);
4784 s = zbc_parse_stmt();
4785 }
4786
4787 dbg_lex_done("%s:%d done", __func__, __LINE__);
4788 RETURN_STATUS(s);
4789}
4790#define zbc_parse_stmt_or_funcdef(...) (zbc_parse_stmt_or_funcdef(__VA_ARGS__) COMMA_SUCCESS)
4791
4792#undef zbc_parse_expr
4793static BC_STATUS zbc_parse_expr(uint8_t flags)
4794{
4795 BcParse *p = &G.prs;
4796 BcInst prev = XC_INST_PRINT;
4797 size_t nexprs = 0, ops_bgn = p->ops.len;
4798 unsigned nparens, nrelops;
4799 bool paren_first, rprn, assign, bin_last, incdec;
4800
4801 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
4802 paren_first = (p->lex == BC_LEX_LPAREN);
4803 nparens = nrelops = 0;
4804 rprn = assign = incdec = false;
4805 bin_last = true;
4806
4807 for (;;) {
4808 bool get_token;
4809 BcStatus s;
4810 BcLexType t = p->lex;
4811
4812 if (!lex_allowed_in_bc_expr(t))
4813 break;
4814
4815 dbg_lex("%s:%d t:%d", __func__, __LINE__, t);
4816 get_token = false;
4817 s = BC_STATUS_SUCCESS;
4818 switch (t) {
4819 case BC_LEX_OP_INC:
4820 case BC_LEX_OP_DEC:
4821 dbg_lex("%s:%d LEX_OP_INC/DEC", __func__, __LINE__);
4822 if (incdec) RETURN_STATUS(bc_error_bad_assignment());
4823 s = zbc_parse_incdec(&prev, &nexprs, flags);
4824 incdec = true;
4825 rprn = bin_last = false;
4826
4827 break;
4828 case XC_LEX_OP_MINUS:
4829 dbg_lex("%s:%d LEX_OP_MINUS", __func__, __LINE__);
4830 s = zbc_parse_minus(&prev, ops_bgn, rprn, bin_last, &nexprs);
4831 rprn = false;
4832
4833 bin_last = (prev == XC_INST_MINUS);
4834 if (bin_last) incdec = false;
4835 break;
4836 case BC_LEX_OP_ASSIGN_POWER:
4837 case BC_LEX_OP_ASSIGN_MULTIPLY:
4838 case BC_LEX_OP_ASSIGN_DIVIDE:
4839 case BC_LEX_OP_ASSIGN_MODULUS:
4840 case BC_LEX_OP_ASSIGN_PLUS:
4841 case BC_LEX_OP_ASSIGN_MINUS:
4842 case BC_LEX_OP_ASSIGN:
4843 dbg_lex("%s:%d LEX_ASSIGNxyz", __func__, __LINE__);
4844 if (prev != XC_INST_VAR && prev != XC_INST_ARRAY_ELEM
4845 && prev != XC_INST_SCALE && prev != XC_INST_IBASE
4846 && prev != XC_INST_OBASE && prev != BC_INST_LAST
4847 ) {
4848 RETURN_STATUS(bc_error_bad_assignment());
4849 }
4850
4851 case XC_LEX_OP_POWER:
4852 case XC_LEX_OP_MULTIPLY:
4853 case XC_LEX_OP_DIVIDE:
4854 case XC_LEX_OP_MODULUS:
4855 case XC_LEX_OP_PLUS:
4856 case XC_LEX_OP_REL_EQ:
4857 case XC_LEX_OP_REL_LE:
4858 case XC_LEX_OP_REL_GE:
4859 case XC_LEX_OP_REL_NE:
4860 case XC_LEX_OP_REL_LT:
4861 case XC_LEX_OP_REL_GT:
4862 case BC_LEX_OP_BOOL_NOT:
4863 case BC_LEX_OP_BOOL_OR:
4864 case BC_LEX_OP_BOOL_AND:
4865 dbg_lex("%s:%d LEX_OP_xyz", __func__, __LINE__);
4866 if (t == BC_LEX_OP_BOOL_NOT) {
4867 if (!bin_last && p->lex_last != BC_LEX_OP_BOOL_NOT)
4868 RETURN_STATUS(bc_error_bad_expression());
4869 } else if (prev == XC_INST_BOOL_NOT) {
4870 RETURN_STATUS(bc_error_bad_expression());
4871 }
4872
4873 nrelops += (t >= XC_LEX_OP_REL_EQ && t <= XC_LEX_OP_REL_GT);
4874 prev = BC_TOKEN_2_INST(t);
4875 bc_parse_operator(t, ops_bgn, &nexprs);
4876 rprn = incdec = false;
4877 get_token = true;
4878 bin_last = (t != BC_LEX_OP_BOOL_NOT);
4879 break;
4880 case BC_LEX_LPAREN:
4881 dbg_lex("%s:%d LEX_LPAREN", __func__, __LINE__);
4882 if (BC_PARSE_LEAF(prev, bin_last, rprn))
4883 RETURN_STATUS(bc_error_bad_expression());
4884 bc_vec_push(&p->ops, &t);
4885 nparens++;
4886 get_token = true;
4887 rprn = incdec = false;
4888 break;
4889 case BC_LEX_RPAREN:
4890 dbg_lex("%s:%d LEX_RPAREN", __func__, __LINE__);
4891
4892
4893
4894
4895 if (bin_last || prev == XC_INST_BOOL_NOT)
4896 RETURN_STATUS(bc_error_bad_expression());
4897 if (nparens == 0) {
4898 goto exit_loop;
4899 }
4900 s = zbc_parse_rightParen(ops_bgn, &nexprs);
4901 nparens--;
4902 get_token = true;
4903 rprn = true;
4904 bin_last = incdec = false;
4905 break;
4906 case XC_LEX_NAME:
4907 dbg_lex("%s:%d LEX_NAME", __func__, __LINE__);
4908 if (BC_PARSE_LEAF(prev, bin_last, rprn))
4909 RETURN_STATUS(bc_error_bad_expression());
4910 s = zbc_parse_name(&prev, flags & ~BC_PARSE_NOCALL);
4911 rprn = (prev == BC_INST_CALL);
4912 bin_last = false;
4913
4914 nexprs++;
4915 break;
4916 case XC_LEX_NUMBER:
4917 dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__);
4918 if (BC_PARSE_LEAF(prev, bin_last, rprn))
4919 RETURN_STATUS(bc_error_bad_expression());
4920 xc_parse_pushNUM();
4921 prev = XC_INST_NUM;
4922 get_token = true;
4923 rprn = bin_last = false;
4924 nexprs++;
4925 break;
4926 case BC_LEX_KEY_IBASE:
4927 case BC_LEX_KEY_LAST:
4928 case BC_LEX_KEY_OBASE:
4929 dbg_lex("%s:%d LEX_IBASE/LAST/OBASE", __func__, __LINE__);
4930 if (BC_PARSE_LEAF(prev, bin_last, rprn))
4931 RETURN_STATUS(bc_error_bad_expression());
4932 prev = (char) (t - BC_LEX_KEY_IBASE + XC_INST_IBASE);
4933 xc_parse_push((char) prev);
4934 get_token = true;
4935 rprn = bin_last = false;
4936 nexprs++;
4937 break;
4938 case BC_LEX_KEY_LENGTH:
4939 case BC_LEX_KEY_SQRT:
4940 dbg_lex("%s:%d LEX_LEN/SQRT", __func__, __LINE__);
4941 if (BC_PARSE_LEAF(prev, bin_last, rprn))
4942 RETURN_STATUS(bc_error_bad_expression());
4943 s = zbc_parse_builtin(t, flags, &prev);
4944 get_token = true;
4945 rprn = bin_last = incdec = false;
4946 nexprs++;
4947 break;
4948 case BC_LEX_KEY_READ:
4949 dbg_lex("%s:%d LEX_READ", __func__, __LINE__);
4950 if (BC_PARSE_LEAF(prev, bin_last, rprn))
4951 RETURN_STATUS(bc_error_bad_expression());
4952 s = zbc_parse_read();
4953 prev = XC_INST_READ;
4954 get_token = true;
4955 rprn = bin_last = incdec = false;
4956 nexprs++;
4957 break;
4958 case BC_LEX_KEY_SCALE:
4959 dbg_lex("%s:%d LEX_SCALE", __func__, __LINE__);
4960 if (BC_PARSE_LEAF(prev, bin_last, rprn))
4961 RETURN_STATUS(bc_error_bad_expression());
4962 s = zbc_parse_scale(&prev, flags);
4963
4964 rprn = bin_last = false;
4965 nexprs++;
4966 break;
4967 default:
4968 RETURN_STATUS(bc_error_bad_token());
4969 }
4970
4971 if (s || G_interrupt)
4972 RETURN_STATUS(BC_STATUS_FAILURE);
4973 if (get_token) {
4974 s = zxc_lex_next();
4975 if (s) RETURN_STATUS(s);
4976 }
4977 }
4978 exit_loop:
4979
4980 while (p->ops.len > ops_bgn) {
4981 BcLexType top = BC_PARSE_TOP_OP(p);
4982 assign = (top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN);
4983
4984 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4985 RETURN_STATUS(bc_error_bad_expression());
4986
4987 xc_parse_push(BC_TOKEN_2_INST(top));
4988
4989 nexprs -= (top != BC_LEX_OP_BOOL_NOT && top != XC_LEX_NEG);
4990 bc_vec_pop(&p->ops);
4991 }
4992
4993 if (prev == XC_INST_BOOL_NOT || nexprs != 1)
4994 RETURN_STATUS(bc_error_bad_expression());
4995
4996 if (!(flags & BC_PARSE_REL) && nrelops) {
4997 BcStatus s;
4998 s = zbc_POSIX_does_not_allow("comparison operators outside if or loops");
4999 if (s) RETURN_STATUS(s);
5000 } else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5001 BcStatus s;
5002 s = zbc_POSIX_requires("exactly one comparison operator per condition");
5003 if (s) RETURN_STATUS(s);
5004 }
5005
5006 if (flags & BC_PARSE_PRINT) {
5007 if (paren_first || !assign)
5008 xc_parse_push(XC_INST_PRINT);
5009 xc_parse_push(XC_INST_POP);
5010 }
5011
5012 dbg_lex_done("%s:%d done", __func__, __LINE__);
5013 RETURN_STATUS(BC_STATUS_SUCCESS);
5014}
5015#define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
5016
5017#endif
5018
5019#if ENABLE_DC
5020
5021static BC_STATUS zdc_parse_register(void)
5022{
5023 BcParse *p = &G.prs;
5024 BcStatus s;
5025
5026 s = zxc_lex_next();
5027 if (s) RETURN_STATUS(s);
5028 if (p->lex != XC_LEX_NAME) RETURN_STATUS(bc_error_bad_token());
5029
5030 xc_parse_pushName(p->lex_strnumbuf.v);
5031
5032 RETURN_STATUS(s);
5033}
5034#define zdc_parse_register(...) (zdc_parse_register(__VA_ARGS__) COMMA_SUCCESS)
5035
5036static void dc_parse_string(void)
5037{
5038 BcParse *p = &G.prs;
5039 char *str;
5040 size_t len = G.prog.strs.len;
5041
5042 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
5043
5044 str = xstrdup(p->lex_strnumbuf.v);
5045 xc_parse_pushInst_and_Index(XC_INST_STR, len);
5046 bc_vec_push(&G.prog.strs, &str);
5047
5048
5049
5050
5051 xc_program_add_fn();
5052 p->func = xc_program_func(p->fidx);
5053
5054 dbg_lex_done("%s:%d done", __func__, __LINE__);
5055}
5056
5057static BC_STATUS zdc_parse_mem(uint8_t inst, bool name, bool store)
5058{
5059 BcStatus s;
5060
5061 xc_parse_push(inst);
5062 if (name) {
5063 s = zdc_parse_register();
5064 if (s) RETURN_STATUS(s);
5065 }
5066
5067 if (store) {
5068 xc_parse_push(DC_INST_SWAP);
5069 xc_parse_push(XC_INST_ASSIGN);
5070 xc_parse_push(XC_INST_POP);
5071 }
5072
5073 RETURN_STATUS(BC_STATUS_SUCCESS);
5074}
5075#define zdc_parse_mem(...) (zdc_parse_mem(__VA_ARGS__) COMMA_SUCCESS)
5076
5077static BC_STATUS zdc_parse_cond(uint8_t inst)
5078{
5079 BcParse *p = &G.prs;
5080 BcStatus s;
5081
5082 xc_parse_push(inst);
5083 xc_parse_push(DC_INST_EXEC_COND);
5084
5085 s = zdc_parse_register();
5086 if (s) RETURN_STATUS(s);
5087
5088 s = zxc_lex_next();
5089 if (s) RETURN_STATUS(s);
5090
5091
5092
5093
5094 if (p->lex == DC_LEX_ELSE) {
5095 s = zdc_parse_register();
5096 if (s) RETURN_STATUS(s);
5097 s = zxc_lex_next();
5098 } else {
5099 xc_parse_push('\0');
5100 }
5101
5102 RETURN_STATUS(s);
5103}
5104#define zdc_parse_cond(...) (zdc_parse_cond(__VA_ARGS__) COMMA_SUCCESS)
5105
5106static BC_STATUS zdc_parse_token(BcLexType t)
5107{
5108 BcStatus s;
5109 uint8_t inst;
5110 bool assign, get_token;
5111
5112 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
5113 s = BC_STATUS_SUCCESS;
5114 get_token = true;
5115 switch (t) {
5116 case XC_LEX_OP_REL_EQ:
5117 case XC_LEX_OP_REL_LE:
5118 case XC_LEX_OP_REL_GE:
5119 case XC_LEX_OP_REL_NE:
5120 case XC_LEX_OP_REL_LT:
5121 case XC_LEX_OP_REL_GT:
5122 dbg_lex("%s:%d LEX_OP_REL_xyz", __func__, __LINE__);
5123 s = zdc_parse_cond(t - XC_LEX_OP_REL_EQ + XC_INST_REL_EQ);
5124 get_token = false;
5125 break;
5126 case DC_LEX_SCOLON:
5127 case DC_LEX_COLON:
5128 dbg_lex("%s:%d LEX_[S]COLON", __func__, __LINE__);
5129 s = zdc_parse_mem(XC_INST_ARRAY_ELEM, true, t == DC_LEX_COLON);
5130 break;
5131 case XC_LEX_STR:
5132 dbg_lex("%s:%d LEX_STR", __func__, __LINE__);
5133 dc_parse_string();
5134 break;
5135 case XC_LEX_NEG:
5136 dbg_lex("%s:%d LEX_NEG", __func__, __LINE__);
5137 s = zxc_lex_next();
5138 if (s) RETURN_STATUS(s);
5139 if (G.prs.lex != XC_LEX_NUMBER)
5140 RETURN_STATUS(bc_error_bad_token());
5141 xc_parse_pushNUM();
5142 xc_parse_push(XC_INST_NEG);
5143 break;
5144 case XC_LEX_NUMBER:
5145 dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__);
5146 xc_parse_pushNUM();
5147 break;
5148 case DC_LEX_READ:
5149 dbg_lex("%s:%d LEX_KEY_READ", __func__, __LINE__);
5150 xc_parse_push(XC_INST_READ);
5151 break;
5152 case DC_LEX_OP_ASSIGN:
5153 case DC_LEX_STORE_PUSH:
5154 dbg_lex("%s:%d LEX_OP_ASSIGN/STORE_PUSH", __func__, __LINE__);
5155 assign = (t == DC_LEX_OP_ASSIGN);
5156 inst = assign ? XC_INST_VAR : DC_INST_PUSH_TO_VAR;
5157 s = zdc_parse_mem(inst, true, assign);
5158 break;
5159 case DC_LEX_LOAD:
5160 case DC_LEX_LOAD_POP:
5161 dbg_lex("%s:%d LEX_OP_LOAD[_POP]", __func__, __LINE__);
5162 inst = t == DC_LEX_LOAD_POP ? DC_INST_PUSH_VAR : DC_INST_LOAD;
5163 s = zdc_parse_mem(inst, true, false);
5164 break;
5165 case DC_LEX_STORE_IBASE:
5166 case DC_LEX_STORE_SCALE:
5167 case DC_LEX_STORE_OBASE:
5168 dbg_lex("%s:%d LEX_OP_STORE_I/OBASE/SCALE", __func__, __LINE__);
5169 inst = t - DC_LEX_STORE_IBASE + XC_INST_IBASE;
5170 s = zdc_parse_mem(inst, false, true);
5171 break;
5172 default:
5173 dbg_lex_done("%s:%d done (bad token)", __func__, __LINE__);
5174 RETURN_STATUS(bc_error_bad_token());
5175 }
5176
5177 if (!s && get_token) s = zxc_lex_next();
5178
5179 dbg_lex_done("%s:%d done", __func__, __LINE__);
5180 RETURN_STATUS(s);
5181}
5182#define zdc_parse_token(...) (zdc_parse_token(__VA_ARGS__) COMMA_SUCCESS)
5183
5184static BC_STATUS zdc_parse_expr(void)
5185{
5186 BcParse *p = &G.prs;
5187 int i;
5188
5189 if (p->lex == XC_LEX_NLINE)
5190 RETURN_STATUS(zxc_lex_next());
5191
5192 i = (int)p->lex - (int)XC_LEX_OP_POWER;
5193 if (i >= 0) {
5194 BcInst inst = dc_LEX_to_INST[i];
5195 if (inst != DC_INST_INVALID) {
5196 xc_parse_push(inst);
5197 RETURN_STATUS(zxc_lex_next());
5198 }
5199 }
5200 RETURN_STATUS(zdc_parse_token(p->lex));
5201}
5202#define zdc_parse_expr(...) (zdc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
5203
5204static BC_STATUS zdc_parse_exprs_until_eof(void)
5205{
5206 BcParse *p = &G.prs;
5207 dbg_lex_enter("%s:%d entered, p->lex:%d", __func__, __LINE__, p->lex);
5208 while (p->lex != XC_LEX_EOF) {
5209 BcStatus s = zdc_parse_expr();
5210 if (s) RETURN_STATUS(s);
5211 }
5212
5213 dbg_lex_done("%s:%d done", __func__, __LINE__);
5214 RETURN_STATUS(BC_STATUS_SUCCESS);
5215}
5216#define zdc_parse_exprs_until_eof(...) (zdc_parse_exprs_until_eof(__VA_ARGS__) COMMA_SUCCESS)
5217
5218#endif
5219
5220
5221
5222
5223
5224#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
5225#define BC_PROG_NUM(r, n) \
5226 ((r)->t != XC_RESULT_ARRAY && (r)->t != XC_RESULT_STR && !BC_PROG_STR(n))
5227
5228#define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n)))
5229#define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n)))
5230
5231static size_t xc_program_index(char *code, size_t *bgn)
5232{
5233 unsigned char *bytes = (void*)(code + *bgn);
5234 unsigned amt;
5235 unsigned i;
5236 size_t res;
5237
5238 amt = *bytes++;
5239 if (amt < SMALL_INDEX_LIMIT) {
5240 *bgn += 1;
5241 return amt;
5242 }
5243 amt -= (SMALL_INDEX_LIMIT - 1);
5244 *bgn += amt + 1;
5245
5246 res = 0;
5247 i = 0;
5248 do {
5249 res |= (size_t)(*bytes++) << i;
5250 i += 8;
5251 } while (--amt != 0);
5252
5253 return res;
5254}
5255
5256static char *xc_program_name(char *code, size_t *bgn)
5257{
5258 code += *bgn;
5259 *bgn += strlen(code) + 1;
5260
5261 return xstrdup(code);
5262}
5263
5264static BcVec* xc_program_dereference(BcVec *vec)
5265{
5266 BcVec *v;
5267 size_t vidx, nidx, i = 0;
5268
5269
5270
5271 vidx = xc_program_index(vec->v, &i);
5272 nidx = xc_program_index(vec->v, &i);
5273
5274 v = bc_vec_item(&G.prog.arrs, vidx);
5275 v = bc_vec_item(v, nidx);
5276
5277
5278
5279 return v;
5280}
5281
5282static BcVec* xc_program_search(char *id, BcType type)
5283{
5284 BcId e, *ptr;
5285 BcVec *v, *map;
5286 size_t i;
5287 int new;
5288 bool var = (type == BC_TYPE_VAR);
5289
5290 v = var ? &G.prog.vars : &G.prog.arrs;
5291 map = var ? &G.prog.var_map : &G.prog.arr_map;
5292
5293 e.name = id;
5294 e.idx = v->len;
5295 new = bc_map_insert(map, &e, &i);
5296
5297 if (new) {
5298 BcVec v2;
5299 bc_array_init(&v2, var);
5300 bc_vec_push(v, &v2);
5301 }
5302
5303 ptr = bc_vec_item(map, i);
5304 if (new) ptr->name = xstrdup(e.name);
5305 return bc_vec_item(v, ptr->idx);
5306}
5307
5308
5309static BC_STATUS zxc_program_num(BcResult *r, BcNum **num)
5310{
5311 switch (r->t) {
5312 case XC_RESULT_STR:
5313 case XC_RESULT_TEMP:
5314 IF_BC(case BC_RESULT_VOID:)
5315 case XC_RESULT_IBASE:
5316 case XC_RESULT_SCALE:
5317 case XC_RESULT_OBASE:
5318 *num = &r->d.n;
5319 break;
5320 case XC_RESULT_CONSTANT: {
5321 BcStatus s;
5322 char *str;
5323 size_t len;
5324
5325 str = *xc_program_const(r->d.id.idx);
5326 len = strlen(str);
5327
5328 bc_num_init(&r->d.n, len);
5329
5330 s = zxc_num_parse(&r->d.n, str, G.prog.ib_t);
5331 if (s) {
5332 bc_num_free(&r->d.n);
5333 RETURN_STATUS(s);
5334 }
5335 *num = &r->d.n;
5336 r->t = XC_RESULT_TEMP;
5337 break;
5338 }
5339 case XC_RESULT_VAR:
5340 case XC_RESULT_ARRAY:
5341 case XC_RESULT_ARRAY_ELEM: {
5342 BcType type = (r->t == XC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
5343 BcVec *v = xc_program_search(r->d.id.name, type);
5344 void *p = bc_vec_top(v);
5345
5346 if (r->t == XC_RESULT_ARRAY_ELEM) {
5347 size_t idx = r->d.id.idx;
5348
5349 v = p;
5350 if (v->size == sizeof(uint8_t))
5351 v = xc_program_dereference(v);
5352
5353 if (v->len <= idx)
5354 bc_array_expand(v, idx + 1);
5355 *num = bc_vec_item(v, idx);
5356 } else {
5357 *num = p;
5358 }
5359 break;
5360 }
5361#if ENABLE_BC
5362 case BC_RESULT_LAST:
5363 *num = &G.prog.last;
5364 break;
5365 case BC_RESULT_ONE:
5366 *num = &G.prog.one;
5367 break;
5368#endif
5369#if SANITY_CHECKS
5370 default:
5371
5372 bb_error_msg_and_die("BUG:%d", r->t);
5373#endif
5374 }
5375
5376 RETURN_STATUS(BC_STATUS_SUCCESS);
5377}
5378#define zxc_program_num(...) (zxc_program_num(__VA_ARGS__) COMMA_SUCCESS)
5379
5380static BC_STATUS zxc_program_binOpPrep(BcResult **l, BcNum **ln,
5381 BcResult **r, BcNum **rn, bool assign)
5382{
5383 BcStatus s;
5384 BcResultType lt, rt;
5385
5386 if (!STACK_HAS_MORE_THAN(&G.prog.results, 1))
5387 RETURN_STATUS(bc_error_stack_has_too_few_elements());
5388
5389 *r = bc_vec_item_rev(&G.prog.results, 0);
5390 *l = bc_vec_item_rev(&G.prog.results, 1);
5391
5392 s = zxc_program_num(*l, ln);
5393 if (s) RETURN_STATUS(s);
5394 s = zxc_program_num(*r, rn);
5395 if (s) RETURN_STATUS(s);
5396
5397 lt = (*l)->t;
5398 rt = (*r)->t;
5399
5400
5401
5402 if (lt == rt && (lt == XC_RESULT_VAR || lt == XC_RESULT_ARRAY_ELEM)) {
5403 s = zxc_program_num(*l, ln);
5404 if (s) RETURN_STATUS(s);
5405 }
5406
5407 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != XC_RESULT_VAR))
5408 RETURN_STATUS(bc_error_variable_is_wrong_type());
5409 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5410 RETURN_STATUS(bc_error_variable_is_wrong_type());
5411
5412 RETURN_STATUS(s);
5413}
5414#define zxc_program_binOpPrep(...) (zxc_program_binOpPrep(__VA_ARGS__) COMMA_SUCCESS)
5415
5416static void xc_program_binOpRetire(BcResult *r)
5417{
5418 r->t = XC_RESULT_TEMP;
5419 bc_vec_pop(&G.prog.results);
5420 bc_result_pop_and_push(r);
5421}
5422
5423
5424static BC_STATUS zxc_program_prep(BcResult **r, BcNum **n)
5425{
5426 BcStatus s;
5427
5428 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
5429 RETURN_STATUS(bc_error_stack_has_too_few_elements());
5430 *r = bc_vec_top(&G.prog.results);
5431
5432 s = zxc_program_num(*r, n);
5433 if (s) RETURN_STATUS(s);
5434
5435 if (!BC_PROG_NUM((*r), (*n)))
5436 RETURN_STATUS(bc_error_variable_is_wrong_type());
5437
5438 RETURN_STATUS(s);
5439}
5440#define zxc_program_prep(...) (zxc_program_prep(__VA_ARGS__) COMMA_SUCCESS)
5441
5442static void xc_program_retire(BcResult *r, BcResultType t)
5443{
5444 r->t = t;
5445 bc_result_pop_and_push(r);
5446}
5447
5448static BC_STATUS zxc_program_op(char inst)
5449{
5450 BcStatus s;
5451 BcResult *opd1, *opd2, res;
5452 BcNum *n1, *n2;
5453
5454 s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5455 if (s) RETURN_STATUS(s);
5456 bc_num_init_DEF_SIZE(&res.d.n);
5457
5458 s = BC_STATUS_SUCCESS;
5459 IF_ERROR_RETURN_POSSIBLE(s =) zxc_program_ops[inst - XC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5460 if (s) goto err;
5461 xc_program_binOpRetire(&res);
5462
5463 RETURN_STATUS(s);
5464 err:
5465 bc_num_free(&res.d.n);
5466 RETURN_STATUS(s);
5467}
5468#define zxc_program_op(...) (zxc_program_op(__VA_ARGS__) COMMA_SUCCESS)
5469
5470static BC_STATUS zxc_program_read(void)
5471{
5472 BcStatus s;
5473 BcParse sv_parse;
5474 BcVec buf;
5475 BcInstPtr ip;
5476 BcFunc *f;
5477
5478 bc_char_vec_init(&buf);
5479 xc_read_line(&buf, stdin);
5480
5481 f = xc_program_func(BC_PROG_READ);
5482 bc_vec_pop_all(&f->code);
5483
5484 sv_parse = G.prs;
5485 xc_parse_create(BC_PROG_READ);
5486
5487
5488 s = zxc_parse_text_init(buf.v);
5489 if (s) goto exec_err;
5490 if (IS_BC) {
5491 IF_BC(s = zbc_parse_expr(0));
5492 } else {
5493 IF_DC(s = zdc_parse_exprs_until_eof());
5494 }
5495 if (s) goto exec_err;
5496 if (G.prs.lex != XC_LEX_NLINE && G.prs.lex != XC_LEX_EOF) {
5497 s = bc_error_at("bad read() expression");
5498 goto exec_err;
5499 }
5500 xc_parse_push(XC_INST_RET);
5501
5502 ip.func = BC_PROG_READ;
5503 ip.inst_idx = 0;
5504 bc_vec_push(&G.prog.exestack, &ip);
5505
5506 exec_err:
5507 xc_parse_free();
5508 G.prs = sv_parse;
5509 bc_vec_free(&buf);
5510 RETURN_STATUS(s);
5511}
5512#define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS)
5513
5514static void xc_program_printString(const char *str)
5515{
5516#if ENABLE_DC
5517 if (!str[0] && IS_DC) {
5518
5519
5520 bb_putchar('\0');
5521 return;
5522 }
5523#endif
5524 while (*str) {
5525 char c = *str++;
5526 if (c == '\\') {
5527 static const char esc[] ALIGN1 = "nabfrt""e\\";
5528 char *n;
5529
5530 c = *str++;
5531 n = strchr(esc, c);
5532 if (!n || !c) {
5533
5534 bb_putchar('\\');
5535 ++G.prog.nchars;
5536
5537 if (!c) break;
5538 } else {
5539 if (n - esc == 0)
5540 G.prog.nchars = SIZE_MAX;
5541 c = "\n\a\b\f\r\t""\\\\""\\"[n - esc];
5542
5543 }
5544 }
5545 putchar(c);
5546 ++G.prog.nchars;
5547 }
5548}
5549
5550static void bc_num_printNewline(void)
5551{
5552 if (G.prog.nchars == G.prog.len - 1) {
5553 bb_putchar('\\');
5554 bb_putchar('\n');
5555 G.prog.nchars = 0;
5556 }
5557}
5558
5559#if ENABLE_DC
5560static FAST_FUNC void dc_num_printChar(size_t num, size_t width, bool radix)
5561{
5562 (void) radix;
5563 bb_putchar((char) num);
5564 G.prog.nchars += width;
5565}
5566#endif
5567
5568static FAST_FUNC void bc_num_printDigits(size_t num, size_t width, bool radix)
5569{
5570 size_t exp, pow;
5571
5572 bc_num_printNewline();
5573 bb_putchar(radix ? '.' : ' ');
5574 ++G.prog.nchars;
5575
5576 bc_num_printNewline();
5577 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
5578 continue;
5579
5580 for (exp = 0; exp < width; pow /= 10, ++G.prog.nchars, ++exp) {
5581 size_t dig;
5582 bc_num_printNewline();
5583 dig = num / pow;
5584 num -= dig * pow;
5585 bb_putchar(((char) dig) + '0');
5586 }
5587}
5588
5589static FAST_FUNC void bc_num_printHex(size_t num, size_t width, bool radix)
5590{
5591 if (radix) {
5592 bc_num_printNewline();
5593 bb_putchar('.');
5594 G.prog.nchars++;
5595 }
5596
5597 bc_num_printNewline();
5598 bb_putchar(bb_hexdigits_upcase[num]);
5599 G.prog.nchars += width;
5600}
5601
5602static void bc_num_printDecimal(BcNum *n)
5603{
5604 size_t i, rdx = n->rdx - 1;
5605
5606 if (n->neg) {
5607 bb_putchar('-');
5608 G.prog.nchars++;
5609 }
5610
5611 for (i = n->len - 1; i < n->len; --i)
5612 bc_num_printHex((size_t) n->num[i], 1, i == rdx);
5613}
5614
5615typedef void (*BcNumDigitOp)(size_t, size_t, bool) FAST_FUNC;
5616
5617static BC_STATUS zxc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNumDigitOp print)
5618{
5619 BcStatus s;
5620 BcVec stack;
5621 BcNum base;
5622 BcDig base_digs[ULONG_NUM_BUFSIZE];
5623 BcNum intp, fracp, digit, frac_len;
5624 unsigned long dig, *ptr;
5625 size_t i;
5626 bool radix;
5627
5628 if (n->len == 0) {
5629 print(0, width, false);
5630 RETURN_STATUS(BC_STATUS_SUCCESS);
5631 }
5632
5633 bc_vec_init(&stack, sizeof(long), NULL);
5634 bc_num_init_and_copy(&intp, n);
5635 bc_num_init(&fracp, n->rdx);
5636 bc_num_init(&digit, width);
5637 bc_num_init(&frac_len, BC_NUM_INT(n));
5638 bc_num_one(&frac_len);
5639 base.cap = ARRAY_SIZE(base_digs);
5640 base.num = base_digs;
5641 bc_num_ulong2num(&base, base_t);
5642
5643 bc_num_truncate(&intp, intp.rdx);
5644 s = zbc_num_sub(n, &intp, &fracp, 0);
5645 if (s) goto err;
5646
5647 while (intp.len != 0) {
5648 s = zbc_num_divmod(&intp, &base, &intp, &digit, 0);
5649 if (s) goto err;
5650 s = zbc_num_ulong(&digit, &dig);
5651 if (s) goto err;
5652 bc_vec_push(&stack, &dig);
5653 }
5654
5655 for (i = 0; i < stack.len; ++i) {
5656 ptr = bc_vec_item_rev(&stack, i);
5657 print(*ptr, width, false);
5658 }
5659
5660 if (!n->rdx) goto err;
5661
5662 for (radix = true; frac_len.len <= n->rdx; radix = false) {
5663 s = zbc_num_mul(&fracp, &base, &fracp, n->rdx);
5664 if (s) goto err;
5665 s = zbc_num_ulong(&fracp, &dig);
5666 if (s) goto err;
5667 bc_num_ulong2num(&intp, dig);
5668 s = zbc_num_sub(&fracp, &intp, &fracp, 0);
5669 if (s) goto err;
5670 print(dig, width, radix);
5671 s = zbc_num_mul(&frac_len, &base, &frac_len, 0);
5672 if (s) goto err;
5673 }
5674 err:
5675 bc_num_free(&frac_len);
5676 bc_num_free(&digit);
5677 bc_num_free(&fracp);
5678 bc_num_free(&intp);
5679 bc_vec_free(&stack);
5680 RETURN_STATUS(s);
5681}
5682#define zxc_num_printNum(...) (zxc_num_printNum(__VA_ARGS__) COMMA_SUCCESS)
5683
5684static BC_STATUS zxc_num_printBase(BcNum *n)
5685{
5686 BcStatus s;
5687 size_t width;
5688 BcNumDigitOp print;
5689 bool neg = n->neg;
5690
5691 if (neg) {
5692 bb_putchar('-');
5693 G.prog.nchars++;
5694 }
5695
5696 n->neg = false;
5697
5698 if (G.prog.ob_t <= 16) {
5699 width = 1;
5700 print = bc_num_printHex;
5701 } else {
5702 unsigned i = G.prog.ob_t - 1;
5703 width = 0;
5704 for (;;) {
5705 width++;
5706 i /= 10;
5707 if (i == 0)
5708 break;
5709 }
5710 print = bc_num_printDigits;
5711 }
5712
5713 s = zxc_num_printNum(n, G.prog.ob_t, width, print);
5714 n->neg = neg;
5715
5716 RETURN_STATUS(s);
5717}
5718#define zxc_num_printBase(...) (zxc_num_printBase(__VA_ARGS__) COMMA_SUCCESS)
5719
5720static BC_STATUS zxc_num_print(BcNum *n, bool newline)
5721{
5722 BcStatus s = BC_STATUS_SUCCESS;
5723
5724 bc_num_printNewline();
5725
5726 if (n->len == 0) {
5727 bb_putchar('0');
5728 ++G.prog.nchars;
5729 } else if (G.prog.ob_t == 10)
5730 bc_num_printDecimal(n);
5731 else
5732 s = zxc_num_printBase(n);
5733
5734 if (newline) {
5735 bb_putchar('\n');
5736 G.prog.nchars = 0;
5737 }
5738
5739 RETURN_STATUS(s);
5740}
5741#define zxc_num_print(...) (zxc_num_print(__VA_ARGS__) COMMA_SUCCESS)
5742
5743#if !ENABLE_DC
5744
5745#define xc_program_print(inst, idx) \
5746 xc_program_print(inst)
5747#endif
5748static BC_STATUS xc_program_print(char inst, size_t idx)
5749{
5750 BcStatus s;
5751 BcResult *r;
5752 BcNum *num;
5753 IF_NOT_DC(size_t idx = 0);
5754
5755 if (!STACK_HAS_MORE_THAN(&G.prog.results, idx))
5756 RETURN_STATUS(bc_error_stack_has_too_few_elements());
5757
5758 r = bc_vec_item_rev(&G.prog.results, idx);
5759#if ENABLE_BC
5760 if (inst == XC_INST_PRINT && r->t == BC_RESULT_VOID)
5761
5762 RETURN_STATUS(BC_STATUS_SUCCESS);
5763#endif
5764 s = zxc_program_num(r, &num);
5765 if (s) RETURN_STATUS(s);
5766
5767 if (BC_PROG_NUM(r, num)) {
5768 s = zxc_num_print(num, inst == XC_INST_PRINT);
5769#if ENABLE_BC
5770 if (!s && IS_BC) bc_num_copy(&G.prog.last, num);
5771#endif
5772 } else {
5773 char *str;
5774
5775 idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : num->rdx;
5776 str = *xc_program_str(idx);
5777
5778 if (inst == XC_INST_PRINT_STR) {
5779 char *nl;
5780 G.prog.nchars += printf("%s", str);
5781 nl = strrchr(str, '\n');
5782 if (nl)
5783 G.prog.nchars = strlen(nl + 1);
5784 } else {
5785 xc_program_printString(str);
5786 if (inst == XC_INST_PRINT)
5787 bb_putchar('\n');
5788 }
5789 }
5790
5791 if (!s && inst != XC_INST_PRINT) bc_vec_pop(&G.prog.results);
5792
5793 RETURN_STATUS(s);
5794}
5795#define zxc_program_print(...) (xc_program_print(__VA_ARGS__) COMMA_SUCCESS)
5796
5797static BC_STATUS zxc_program_negate(void)
5798{
5799 BcStatus s;
5800 BcResult res, *ptr;
5801 BcNum *num;
5802
5803 s = zxc_program_prep(&ptr, &num);
5804 if (s) RETURN_STATUS(s);
5805
5806 bc_num_init_and_copy(&res.d.n, num);
5807 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5808
5809 xc_program_retire(&res, XC_RESULT_TEMP);
5810
5811 RETURN_STATUS(s);
5812}
5813#define zxc_program_negate(...) (zxc_program_negate(__VA_ARGS__) COMMA_SUCCESS)
5814
5815static BC_STATUS zxc_program_logical(char inst)
5816{
5817 BcStatus s;
5818 BcResult *opd1, *opd2, res;
5819 BcNum *n1, *n2;
5820 ssize_t cond;
5821
5822 s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5823 if (s) RETURN_STATUS(s);
5824
5825 bc_num_init_DEF_SIZE(&res.d.n);
5826
5827 if (inst == XC_INST_BOOL_AND)
5828 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5829 else if (inst == XC_INST_BOOL_OR)
5830 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5831 else {
5832 cond = bc_num_cmp(n1, n2);
5833 switch (inst) {
5834 case XC_INST_REL_EQ:
5835 cond = (cond == 0);
5836 break;
5837 case XC_INST_REL_LE:
5838 cond = (cond <= 0);
5839 break;
5840 case XC_INST_REL_GE:
5841 cond = (cond >= 0);
5842 break;
5843 case XC_INST_REL_LT:
5844 cond = (cond < 0);
5845 break;
5846 case XC_INST_REL_GT:
5847 cond = (cond > 0);
5848 break;
5849 default:
5850
5851 break;
5852 }
5853 }
5854
5855 if (cond) bc_num_one(&res.d.n);
5856
5857
5858 xc_program_binOpRetire(&res);
5859
5860 RETURN_STATUS(s);
5861}
5862#define zxc_program_logical(...) (zxc_program_logical(__VA_ARGS__) COMMA_SUCCESS)
5863
5864#if ENABLE_DC
5865static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push)
5866{
5867 BcNum n2;
5868 BcResult res;
5869
5870 memset(&n2, 0, sizeof(BcNum));
5871 n2.rdx = res.d.id.idx = r->d.id.idx;
5872 res.t = XC_RESULT_STR;
5873
5874 if (!push) {
5875 if (!STACK_HAS_MORE_THAN(&G.prog.results, 1))
5876 RETURN_STATUS(bc_error_stack_has_too_few_elements());
5877 bc_vec_pop(v);
5878 bc_vec_pop(&G.prog.results);
5879 }
5880
5881 bc_result_pop_and_push(&res);
5882 bc_vec_push(v, &n2);
5883
5884 RETURN_STATUS(BC_STATUS_SUCCESS);
5885}
5886#define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS)
5887#endif
5888
5889static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, BcType t)
5890{
5891 BcStatus s;
5892 BcResult *ptr, r;
5893 BcVec *vec;
5894 BcNum *n;
5895 bool var = (t == BC_TYPE_VAR);
5896
5897 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
5898 RETURN_STATUS(bc_error_stack_has_too_few_elements());
5899
5900 ptr = bc_vec_top(&G.prog.results);
5901 if ((ptr->t == XC_RESULT_ARRAY) == var)
5902 RETURN_STATUS(bc_error_variable_is_wrong_type());
5903 vec = xc_program_search(name, t);
5904
5905#if ENABLE_DC
5906 if (ptr->t == XC_RESULT_STR) {
5907 if (!var)
5908 RETURN_STATUS(bc_error_variable_is_wrong_type());
5909 RETURN_STATUS(zdc_program_assignStr(ptr, vec, true));
5910 }
5911#endif
5912
5913 s = zxc_program_num(ptr, &n);
5914 if (s) RETURN_STATUS(s);
5915
5916
5917 vec = xc_program_search(name, t);
5918
5919 if (var) {
5920 bc_num_init_DEF_SIZE(&r.d.n);
5921 bc_num_copy(&r.d.n, n);
5922 } else {
5923 BcVec *v = (BcVec*) n;
5924 bool ref, ref_size;
5925
5926 ref = (v->size == sizeof(BcVec) && t != BC_TYPE_ARRAY);
5927 ref_size = (v->size == sizeof(uint8_t));
5928
5929 if (ref || (ref_size && t == BC_TYPE_REF)) {
5930 bc_vec_init(&r.d.v, sizeof(uint8_t), NULL);
5931 if (ref) {
5932 size_t vidx, idx;
5933 BcId id;
5934
5935 id.name = ptr->d.id.name;
5936 v = xc_program_search(ptr->d.id.name, BC_TYPE_REF);
5937
5938
5939 vec = xc_program_search(name, t);
5940
5941 vidx = bc_map_find_exact(&G.prog.arr_map, &id);
5942
5943 vidx = ((BcId*) bc_vec_item(&G.prog.arr_map, vidx))->idx;
5944 idx = v->len - 1;
5945
5946 bc_vec_pushIndex(&r.d.v, vidx);
5947 bc_vec_pushIndex(&r.d.v, idx);
5948 }
5949
5950 else bc_vec_npush(&r.d.v, v->len, v->v);
5951
5952
5953 goto ret;
5954 }
5955
5956 if (ref_size && t != BC_TYPE_REF)
5957 v = xc_program_dereference(v);
5958
5959 bc_array_init(&r.d.v, true);
5960 bc_array_copy(&r.d.v, v);
5961 }
5962 ret:
5963 bc_vec_push(vec, &r.d);
5964 bc_vec_pop(&G.prog.results);
5965
5966 RETURN_STATUS(s);
5967}
5968#define zxc_program_popResultAndCopyToVar(...) (zxc_program_popResultAndCopyToVar(__VA_ARGS__) COMMA_SUCCESS)
5969
5970static BC_STATUS zxc_program_assign(char inst)
5971{
5972 BcStatus s;
5973 BcResult *left, *right, res;
5974 BcNum *l, *r;
5975 bool assign = (inst == XC_INST_ASSIGN);
5976 bool ib, sc;
5977
5978 s = zxc_program_binOpPrep(&left, &l, &right, &r, assign);
5979 if (s) RETURN_STATUS(s);
5980
5981 ib = left->t == XC_RESULT_IBASE;
5982 sc = left->t == XC_RESULT_SCALE;
5983
5984#if ENABLE_DC
5985 if (right->t == XC_RESULT_STR) {
5986 BcVec *v;
5987
5988 if (left->t != XC_RESULT_VAR)
5989 RETURN_STATUS(bc_error_variable_is_wrong_type());
5990 v = xc_program_search(left->d.id.name, BC_TYPE_VAR);
5991
5992 RETURN_STATUS(zdc_program_assignStr(right, v, false));
5993 }
5994#endif
5995
5996 if (left->t == XC_RESULT_CONSTANT
5997 || left->t == XC_RESULT_TEMP
5998 IF_BC(|| left->t == BC_RESULT_VOID)
5999 ) {
6000 RETURN_STATUS(bc_error_bad_assignment());
6001 }
6002
6003#if ENABLE_BC
6004 if (assign)
6005 bc_num_copy(l, r);
6006 else {
6007 s = BC_STATUS_SUCCESS;
6008 IF_ERROR_RETURN_POSSIBLE(s =) zxc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
6009 }
6010 if (s) RETURN_STATUS(s);
6011#else
6012 bc_num_copy(l, r);
6013#endif
6014
6015 if (ib || sc || left->t == XC_RESULT_OBASE) {
6016 static const char *const msg[] ALIGN_PTR = {
6017 "bad ibase; must be [2,16]",
6018 "bad obase; must be [2,"BC_MAX_OBASE_STR"]",
6019 "bad scale; must be [0,"BC_MAX_SCALE_STR"]",
6020 };
6021 size_t *ptr;
6022 size_t max;
6023 unsigned long val;
6024
6025 s = zbc_num_ulong(l, &val);
6026 if (s) RETURN_STATUS(s);
6027 s = left->t - XC_RESULT_IBASE;
6028 if (sc) {
6029 max = BC_MAX_SCALE;
6030 ptr = &G.prog.scale;
6031 } else {
6032 if (val < 2)
6033 RETURN_STATUS(bc_error(msg[s]));
6034 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
6035 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
6036 }
6037
6038 if (val > max)
6039 RETURN_STATUS(bc_error(msg[s]));
6040
6041 *ptr = (size_t) val;
6042 s = BC_STATUS_SUCCESS;
6043 }
6044
6045 bc_num_init_and_copy(&res.d.n, l);
6046 xc_program_binOpRetire(&res);
6047
6048 RETURN_STATUS(s);
6049}
6050#define zxc_program_assign(...) (zxc_program_assign(__VA_ARGS__) COMMA_SUCCESS)
6051
6052#if !ENABLE_DC
6053#define xc_program_pushVar(code, bgn, pop, copy) \
6054 xc_program_pushVar(code, bgn)
6055
6056#endif
6057static BC_STATUS xc_program_pushVar(char *code, size_t *bgn,
6058 bool pop, bool copy)
6059{
6060 BcResult r;
6061 char *name = xc_program_name(code, bgn);
6062
6063 r.t = XC_RESULT_VAR;
6064 r.d.id.name = name;
6065
6066#if ENABLE_DC
6067 if (pop || copy) {
6068 BcVec *v = xc_program_search(name, BC_TYPE_VAR);
6069 BcNum *num = bc_vec_top(v);
6070
6071 free(name);
6072 if (!STACK_HAS_MORE_THAN(v, 1 - copy)) {
6073 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6074 }
6075
6076 if (!BC_PROG_STR(num)) {
6077 r.t = XC_RESULT_TEMP;
6078 bc_num_init_DEF_SIZE(&r.d.n);
6079 bc_num_copy(&r.d.n, num);
6080 } else {
6081 r.t = XC_RESULT_STR;
6082 r.d.id.idx = num->rdx;
6083 }
6084
6085 if (!copy) bc_vec_pop(v);
6086 }
6087#endif
6088
6089 bc_vec_push(&G.prog.results, &r);
6090
6091 RETURN_STATUS(BC_STATUS_SUCCESS);
6092}
6093#define zxc_program_pushVar(...) (xc_program_pushVar(__VA_ARGS__) COMMA_SUCCESS)
6094
6095static BC_STATUS zbc_program_pushArray(char *code, size_t *bgn, char inst)
6096{
6097 BcStatus s = BC_STATUS_SUCCESS;
6098 BcResult r;
6099 BcNum *num;
6100
6101 r.d.id.name = xc_program_name(code, bgn);
6102
6103 if (inst == XC_INST_ARRAY) {
6104 r.t = XC_RESULT_ARRAY;
6105 bc_vec_push(&G.prog.results, &r);
6106 } else {
6107 BcResult *operand;
6108 unsigned long temp;
6109
6110 s = zxc_program_prep(&operand, &num);
6111 if (s) goto err;
6112 s = zbc_num_ulong(num, &temp);
6113 if (s) goto err;
6114
6115 if (temp > BC_MAX_DIM) {
6116 s = bc_error("array too long; must be [1,"BC_MAX_DIM_STR"]");
6117 goto err;
6118 }
6119
6120 r.d.id.idx = (size_t) temp;
6121 xc_program_retire(&r, XC_RESULT_ARRAY_ELEM);
6122 }
6123 err:
6124 if (s) free(r.d.id.name);
6125 RETURN_STATUS(s);
6126}
6127#define zbc_program_pushArray(...) (zbc_program_pushArray(__VA_ARGS__) COMMA_SUCCESS)
6128
6129#if ENABLE_BC
6130static BC_STATUS zbc_program_incdec(char inst)
6131{
6132 BcStatus s;
6133 BcResult *ptr, res, copy;
6134 BcNum *num;
6135 char inst2 = inst;
6136
6137 s = zxc_program_prep(&ptr, &num);
6138 if (s) RETURN_STATUS(s);
6139
6140 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6141 copy.t = XC_RESULT_TEMP;
6142 bc_num_init_and_copy(©.d.n, num);
6143 }
6144
6145 res.t = BC_RESULT_ONE;
6146 inst = (inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST)
6147 ? BC_INST_ASSIGN_PLUS
6148 : BC_INST_ASSIGN_MINUS;
6149
6150 bc_vec_push(&G.prog.results, &res);
6151 s = zxc_program_assign(inst);
6152 if (s) RETURN_STATUS(s);
6153
6154 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6155 bc_result_pop_and_push(©);
6156 }
6157
6158 RETURN_STATUS(s);
6159}
6160#define zbc_program_incdec(...) (zbc_program_incdec(__VA_ARGS__) COMMA_SUCCESS)
6161
6162static BC_STATUS zbc_program_call(char *code, size_t *idx)
6163{
6164 BcInstPtr ip;
6165 size_t i, nparams;
6166 BcId *a;
6167 BcFunc *func;
6168
6169 nparams = xc_program_index(code, idx);
6170 ip.func = xc_program_index(code, idx);
6171 func = xc_program_func(ip.func);
6172
6173 if (func->code.len == 0) {
6174 RETURN_STATUS(bc_error("undefined function"));
6175 }
6176 if (nparams != func->nparams) {
6177 RETURN_STATUS(bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams));
6178 }
6179 ip.inst_idx = 0;
6180
6181 for (i = 0; i < nparams; ++i) {
6182 BcResult *arg;
6183 BcStatus s;
6184 bool arr;
6185
6186 a = bc_vec_item(&func->autos, nparams - 1 - i);
6187 arg = bc_vec_top(&G.prog.results);
6188
6189 arr = (a->idx == BC_TYPE_ARRAY || a->idx == BC_TYPE_REF);
6190
6191 if (arr != (arg->t == XC_RESULT_ARRAY)
6192
6193 ) {
6194 RETURN_STATUS(bc_error_variable_is_wrong_type());
6195 }
6196 s = zxc_program_popResultAndCopyToVar(a->name, (BcType) a->idx);
6197 if (s) RETURN_STATUS(s);
6198 }
6199
6200 a = bc_vec_item(&func->autos, i);
6201 for (; i < func->autos.len; i++, a++) {
6202 BcVec *v;
6203
6204 v = xc_program_search(a->name, (BcType) a->idx);
6205 if (a->idx == BC_TYPE_VAR) {
6206 BcNum n2;
6207 bc_num_init_DEF_SIZE(&n2);
6208 bc_vec_push(v, &n2);
6209 } else {
6210
6211 BcVec v2;
6212 bc_array_init(&v2, true);
6213 bc_vec_push(v, &v2);
6214 }
6215 }
6216
6217 bc_vec_push(&G.prog.exestack, &ip);
6218
6219 RETURN_STATUS(BC_STATUS_SUCCESS);
6220}
6221#define zbc_program_call(...) (zbc_program_call(__VA_ARGS__) COMMA_SUCCESS)
6222
6223static BC_STATUS zbc_program_return(char inst)
6224{
6225 BcResult res;
6226 BcFunc *f;
6227 BcId *a;
6228 size_t i;
6229 BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
6230
6231 f = xc_program_func(ip->func);
6232
6233 res.t = XC_RESULT_TEMP;
6234 if (inst == XC_INST_RET) {
6235
6236
6237
6238 BcStatus s;
6239 BcNum *num;
6240 BcResult *operand = bc_vec_top(&G.prog.results);
6241
6242 s = zxc_program_num(operand, &num);
6243 if (s) RETURN_STATUS(s);
6244 bc_num_init_and_copy(&res.d.n, num);
6245 bc_vec_pop(&G.prog.results);
6246 } else {
6247 if (f->voidfunc)
6248 res.t = BC_RESULT_VOID;
6249 bc_num_init_DEF_SIZE(&res.d.n);
6250
6251 }
6252 bc_vec_push(&G.prog.results, &res);
6253
6254 bc_vec_pop(&G.prog.exestack);
6255
6256
6257 a = (void*)f->autos.v;
6258 for (i = 0; i < f->autos.len; i++, a++) {
6259 BcVec *v;
6260 v = xc_program_search(a->name, (BcType) a->idx);
6261 bc_vec_pop(v);
6262 }
6263
6264 RETURN_STATUS(BC_STATUS_SUCCESS);
6265}
6266#define zbc_program_return(...) (zbc_program_return(__VA_ARGS__) COMMA_SUCCESS)
6267#endif
6268
6269static unsigned long xc_program_scale(BcNum *n)
6270{
6271 return (unsigned long) n->rdx;
6272}
6273
6274static unsigned long xc_program_len(BcNum *n)
6275{
6276 size_t len = n->len;
6277
6278 if (n->rdx != len)
6279
6280
6281
6282 return len != 0 ? len : (IS_BC ? n->rdx : 1);
6283
6284
6285
6286 for (;;) {
6287 if (len == 0) break;
6288 len--;
6289 if (n->num[len] != 0) break;
6290 }
6291 return len + 1;
6292}
6293
6294static BC_STATUS zxc_program_builtin(char inst)
6295{
6296 BcStatus s;
6297 BcResult *opnd;
6298 BcNum *num;
6299 BcResult res;
6300 bool len = (inst == XC_INST_LENGTH);
6301
6302 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6303 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6304 opnd = bc_vec_top(&G.prog.results);
6305
6306 s = zxc_program_num(opnd, &num);
6307 if (s) RETURN_STATUS(s);
6308
6309#if ENABLE_DC
6310 if (!BC_PROG_NUM(opnd, num) && !len)
6311 RETURN_STATUS(bc_error_variable_is_wrong_type());
6312#endif
6313
6314 bc_num_init_DEF_SIZE(&res.d.n);
6315
6316 if (inst == XC_INST_SQRT)
6317 s = zbc_num_sqrt(num, &res.d.n, G.prog.scale);
6318#if ENABLE_BC
6319 else if (len && opnd->t == XC_RESULT_ARRAY) {
6320 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6321 }
6322#endif
6323#if ENABLE_DC
6324 else if (len && !BC_PROG_NUM(opnd, num)) {
6325 char **str;
6326 size_t idx = opnd->t == XC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6327
6328 str = xc_program_str(idx);
6329 bc_num_ulong2num(&res.d.n, strlen(*str));
6330 }
6331#endif
6332 else {
6333
6334
6335 bc_num_ulong2num(&res.d.n, len ? xc_program_len(num) : xc_program_scale(num));
6336 }
6337
6338 xc_program_retire(&res, XC_RESULT_TEMP);
6339
6340 RETURN_STATUS(s);
6341}
6342#define zxc_program_builtin(...) (zxc_program_builtin(__VA_ARGS__) COMMA_SUCCESS)
6343
6344#if ENABLE_DC
6345static BC_STATUS zdc_program_divmod(void)
6346{
6347 BcStatus s;
6348 BcResult *opd1, *opd2, res, res2;
6349 BcNum *n1, *n2;
6350
6351 s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6352 if (s) RETURN_STATUS(s);
6353
6354 bc_num_init_DEF_SIZE(&res.d.n);
6355 bc_num_init(&res2.d.n, n2->len);
6356
6357 s = zbc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6358 if (s) goto err;
6359
6360 xc_program_binOpRetire(&res2);
6361 res.t = XC_RESULT_TEMP;
6362 bc_vec_push(&G.prog.results, &res);
6363
6364 RETURN_STATUS(s);
6365 err:
6366 bc_num_free(&res2.d.n);
6367 bc_num_free(&res.d.n);
6368 RETURN_STATUS(s);
6369}
6370#define zdc_program_divmod(...) (zdc_program_divmod(__VA_ARGS__) COMMA_SUCCESS)
6371
6372static BC_STATUS zdc_program_modexp(void)
6373{
6374 BcStatus s;
6375 BcResult *r1, *r2, *r3, res;
6376 BcNum *n1, *n2, *n3;
6377
6378 if (!STACK_HAS_MORE_THAN(&G.prog.results, 2))
6379 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6380 s = zxc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6381 if (s) RETURN_STATUS(s);
6382
6383 r1 = bc_vec_item_rev(&G.prog.results, 2);
6384 s = zxc_program_num(r1, &n1);
6385 if (s) RETURN_STATUS(s);
6386 if (!BC_PROG_NUM(r1, n1))
6387 RETURN_STATUS(bc_error_variable_is_wrong_type());
6388
6389
6390 if (r1->t == XC_RESULT_VAR || r1->t == XC_RESULT_ARRAY_ELEM) {
6391 if (r1->t == r2->t) {
6392 s = zxc_program_num(r2, &n2);
6393 if (s) RETURN_STATUS(s);
6394 }
6395 if (r1->t == r3->t) {
6396 s = zxc_program_num(r3, &n3);
6397 if (s) RETURN_STATUS(s);
6398 }
6399 }
6400
6401 bc_num_init(&res.d.n, n3->len);
6402 s = zdc_num_modexp(n1, n2, n3, &res.d.n);
6403 if (s) goto err;
6404
6405 bc_vec_pop(&G.prog.results);
6406 xc_program_binOpRetire(&res);
6407
6408 RETURN_STATUS(s);
6409 err:
6410 bc_num_free(&res.d.n);
6411 RETURN_STATUS(s);
6412}
6413#define zdc_program_modexp(...) (zdc_program_modexp(__VA_ARGS__) COMMA_SUCCESS)
6414
6415static void dc_program_stackLen(void)
6416{
6417 BcResult res;
6418 size_t len = G.prog.results.len;
6419
6420 res.t = XC_RESULT_TEMP;
6421
6422 bc_num_init_DEF_SIZE(&res.d.n);
6423 bc_num_ulong2num(&res.d.n, len);
6424 bc_vec_push(&G.prog.results, &res);
6425}
6426
6427static BC_STATUS zdc_program_asciify(void)
6428{
6429 BcStatus s;
6430 BcResult *r, res;
6431 BcNum *num, n;
6432 char **strs;
6433 char *str;
6434 char c;
6435 size_t idx;
6436
6437 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6438 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6439
6440 r = bc_vec_top(&G.prog.results);
6441 s = zxc_program_num(r, &num);
6442 if (s) RETURN_STATUS(s);
6443
6444 if (BC_PROG_NUM(r, num)) {
6445 unsigned long val;
6446 BcNum strmb;
6447 BcDig strmb_digs[ULONG_NUM_BUFSIZE];
6448
6449 bc_num_init_DEF_SIZE(&n);
6450 bc_num_copy(&n, num);
6451 bc_num_truncate(&n, n.rdx);
6452
6453 strmb.cap = ARRAY_SIZE(strmb_digs);
6454 strmb.num = strmb_digs;
6455 bc_num_ulong2num(&strmb, 0x100);
6456
6457 s = zbc_num_mod(&n, &strmb, &n, 0);
6458 if (s) goto num_err;
6459 s = zbc_num_ulong(&n, &val);
6460 if (s) goto num_err;
6461
6462 c = (char) val;
6463
6464 bc_num_free(&n);
6465 } else {
6466 char *sp;
6467 idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : num->rdx;
6468 sp = *xc_program_str(idx);
6469 c = sp[0];
6470 }
6471
6472 strs = (void*)G.prog.strs.v;
6473 for (idx = 0; idx < G.prog.strs.len; idx++) {
6474 if (strs[idx][0] == c && strs[idx][1] == '\0') {
6475 goto dup;
6476 }
6477 }
6478 str = xzalloc(2);
6479 str[0] = c;
6480
6481 idx = bc_vec_push(&G.prog.strs, &str);
6482
6483
6484
6485 xc_program_add_fn();
6486 dup:
6487 res.t = XC_RESULT_STR;
6488 res.d.id.idx = idx;
6489 bc_result_pop_and_push(&res);
6490
6491 RETURN_STATUS(BC_STATUS_SUCCESS);
6492 num_err:
6493 bc_num_free(&n);
6494 RETURN_STATUS(s);
6495}
6496#define zdc_program_asciify(...) (zdc_program_asciify(__VA_ARGS__) COMMA_SUCCESS)
6497
6498static BC_STATUS zdc_program_printStream(void)
6499{
6500 BcStatus s;
6501 BcResult *r;
6502 BcNum *n;
6503 size_t idx;
6504
6505 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6506 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6507 r = bc_vec_top(&G.prog.results);
6508
6509 s = zxc_program_num(r, &n);
6510 if (s) RETURN_STATUS(s);
6511
6512 if (BC_PROG_NUM(r, n)) {
6513 s = zxc_num_printNum(n, 0x100, 1, dc_num_printChar);
6514 } else {
6515 char *str;
6516 idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : n->rdx;
6517 str = *xc_program_str(idx);
6518 fputs_stdout(str);
6519 }
6520
6521 RETURN_STATUS(s);
6522}
6523#define zdc_program_printStream(...) (zdc_program_printStream(__VA_ARGS__) COMMA_SUCCESS)
6524
6525static BC_STATUS zdc_program_nquit(void)
6526{
6527 BcStatus s;
6528 BcResult *opnd;
6529 BcNum *num;
6530 unsigned long val;
6531
6532 s = zxc_program_prep(&opnd, &num);
6533 if (s) RETURN_STATUS(s);
6534 s = zbc_num_ulong(num, &val);
6535 if (s) RETURN_STATUS(s);
6536
6537 bc_vec_pop(&G.prog.results);
6538
6539 if (G.prog.exestack.len < val)
6540 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6541 if (G.prog.exestack.len == val) {
6542 QUIT_OR_RETURN_TO_MAIN;
6543 }
6544
6545 bc_vec_npop(&G.prog.exestack, val);
6546
6547 RETURN_STATUS(s);
6548}
6549#define zdc_program_nquit(...) (zdc_program_nquit(__VA_ARGS__) COMMA_SUCCESS)
6550
6551static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
6552{
6553 BcStatus s = BC_STATUS_SUCCESS;
6554 BcResult *r;
6555 BcFunc *f;
6556 BcInstPtr ip;
6557 size_t fidx, sidx;
6558
6559 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6560 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6561
6562 r = bc_vec_top(&G.prog.results);
6563
6564 if (cond) {
6565 BcNum *n = n;
6566 bool exec;
6567 char *name;
6568 char *then_name = xc_program_name(code, bgn);
6569 char *else_name = NULL;
6570
6571 if (code[*bgn] == '\0')
6572 (*bgn) += 1;
6573 else
6574 else_name = xc_program_name(code, bgn);
6575
6576 exec = r->d.n.len != 0;
6577 name = then_name;
6578 if (!exec && else_name != NULL) {
6579 exec = true;
6580 name = else_name;
6581 }
6582
6583 if (exec) {
6584 BcVec *v;
6585 v = xc_program_search(name, BC_TYPE_VAR);
6586 n = bc_vec_top(v);
6587 }
6588
6589 free(then_name);
6590 free(else_name);
6591
6592 if (!exec) goto exit;
6593 if (!BC_PROG_STR(n)) {
6594 s = bc_error_variable_is_wrong_type();
6595 goto exit;
6596 }
6597
6598 sidx = n->rdx;
6599 } else {
6600 if (r->t == XC_RESULT_STR) {
6601 sidx = r->d.id.idx;
6602 } else if (r->t == XC_RESULT_VAR) {
6603 BcNum *n;
6604 s = zxc_program_num(r, &n);
6605 if (s || !BC_PROG_STR(n)) goto exit;
6606 sidx = n->rdx;
6607 } else
6608 goto exit_nopop;
6609 }
6610
6611 fidx = sidx + BC_PROG_REQ_FUNCS;
6612
6613 f = xc_program_func(fidx);
6614
6615 if (f->code.len == 0) {
6616 BcParse sv_parse;
6617 char *str;
6618
6619 sv_parse = G.prs;
6620 xc_parse_create(fidx);
6621 str = *xc_program_str(sidx);
6622 s = zxc_parse_text_init(str);
6623 if (s) goto err;
6624
6625 s = zdc_parse_exprs_until_eof();
6626 if (s) goto err;
6627 xc_parse_push(DC_INST_POP_EXEC);
6628 if (G.prs.lex != XC_LEX_EOF)
6629 s = bc_error_bad_expression();
6630 xc_parse_free();
6631 G.prs = sv_parse;
6632 if (s) {
6633 err:
6634 bc_vec_pop_all(&f->code);
6635 goto exit;
6636 }
6637 }
6638
6639 ip.inst_idx = 0;
6640 ip.func = fidx;
6641
6642 bc_vec_pop(&G.prog.results);
6643 bc_vec_push(&G.prog.exestack, &ip);
6644
6645 RETURN_STATUS(BC_STATUS_SUCCESS);
6646 exit:
6647 bc_vec_pop(&G.prog.results);
6648 exit_nopop:
6649 RETURN_STATUS(s);
6650}
6651#define zdc_program_execStr(...) (zdc_program_execStr(__VA_ARGS__) COMMA_SUCCESS)
6652#endif
6653
6654static void xc_program_pushGlobal(char inst)
6655{
6656 BcResult res;
6657 unsigned long val;
6658
6659 res.t = inst - XC_INST_IBASE + XC_RESULT_IBASE;
6660 if (inst == XC_INST_IBASE)
6661 val = (unsigned long) G.prog.ib_t;
6662 else if (inst == XC_INST_SCALE)
6663 val = (unsigned long) G.prog.scale;
6664 else
6665 val = (unsigned long) G.prog.ob_t;
6666
6667 bc_num_init_DEF_SIZE(&res.d.n);
6668 bc_num_ulong2num(&res.d.n, val);
6669 bc_vec_push(&G.prog.results, &res);
6670}
6671
6672static BC_STATUS zxc_program_exec(void)
6673{
6674 BcResult r, *ptr;
6675 BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
6676 BcFunc *func = xc_program_func(ip->func);
6677 char *code = func->code.v;
6678
6679 dbg_exec("func:%zd bytes:%zd ip:%zd results.len:%d",
6680 ip->func, func->code.len, ip->inst_idx, G.prog.results.len);
6681 while (ip->inst_idx < func->code.len) {
6682 BcStatus s = BC_STATUS_SUCCESS;
6683 char inst = code[ip->inst_idx++];
6684
6685 dbg_exec("inst at %zd:%d results.len:%d", ip->inst_idx - 1, inst, G.prog.results.len);
6686 switch (inst) {
6687 case XC_INST_RET:
6688 if (IS_DC) {
6689 bc_vec_pop(&G.prog.exestack);
6690 goto read_updated_ip;
6691 }
6692
6693#if ENABLE_BC
6694 case BC_INST_RET0:
6695 dbg_exec("BC_INST_RET[0]:");
6696 s = zbc_program_return(inst);
6697 goto read_updated_ip;
6698 case BC_INST_JUMP_ZERO: {
6699 BcNum *num;
6700 bool zero;
6701 dbg_exec("BC_INST_JUMP_ZERO:");
6702 s = zxc_program_prep(&ptr, &num);
6703 if (s) RETURN_STATUS(s);
6704 zero = (bc_num_cmp(num, &G.prog.zero) == 0);
6705 bc_vec_pop(&G.prog.results);
6706 if (!zero) {
6707 xc_program_index(code, &ip->inst_idx);
6708 break;
6709 }
6710
6711 }
6712 case BC_INST_JUMP: {
6713 size_t idx = xc_program_index(code, &ip->inst_idx);
6714 size_t *addr = bc_vec_item(&func->labels, idx);
6715 dbg_exec("BC_INST_JUMP: to %ld", (long)*addr);
6716 ip->inst_idx = *addr;
6717 break;
6718 }
6719 case BC_INST_CALL:
6720 dbg_exec("BC_INST_CALL:");
6721 s = zbc_program_call(code, &ip->inst_idx);
6722 goto read_updated_ip;
6723 case BC_INST_INC_PRE:
6724 case BC_INST_DEC_PRE:
6725 case BC_INST_INC_POST:
6726 case BC_INST_DEC_POST:
6727 dbg_exec("BC_INST_INCDEC:");
6728 s = zbc_program_incdec(inst);
6729 break;
6730 case BC_INST_HALT:
6731 dbg_exec("BC_INST_HALT:");
6732 QUIT_OR_RETURN_TO_MAIN;
6733 break;
6734 case XC_INST_BOOL_OR:
6735 case XC_INST_BOOL_AND:
6736#endif
6737 case XC_INST_REL_EQ:
6738 case XC_INST_REL_LE:
6739 case XC_INST_REL_GE:
6740 case XC_INST_REL_NE:
6741 case XC_INST_REL_LT:
6742 case XC_INST_REL_GT:
6743 dbg_exec("BC_INST_BOOL:");
6744 s = zxc_program_logical(inst);
6745 break;
6746 case XC_INST_READ:
6747 dbg_exec("XC_INST_READ:");
6748 s = zxc_program_read();
6749 goto read_updated_ip;
6750 case XC_INST_VAR:
6751 dbg_exec("XC_INST_VAR:");
6752 s = zxc_program_pushVar(code, &ip->inst_idx, false, false);
6753 break;
6754 case XC_INST_ARRAY_ELEM:
6755 case XC_INST_ARRAY:
6756 dbg_exec("XC_INST_ARRAY[_ELEM]:");
6757 s = zbc_program_pushArray(code, &ip->inst_idx, inst);
6758 break;
6759#if ENABLE_BC
6760 case BC_INST_LAST:
6761 dbg_exec("BC_INST_LAST:");
6762 r.t = BC_RESULT_LAST;
6763 bc_vec_push(&G.prog.results, &r);
6764 break;
6765#endif
6766 case XC_INST_IBASE:
6767 case XC_INST_OBASE:
6768 case XC_INST_SCALE:
6769 dbg_exec("XC_INST_internalvar(%d):", inst - XC_INST_IBASE);
6770 xc_program_pushGlobal(inst);
6771 break;
6772 case XC_INST_SCALE_FUNC:
6773 case XC_INST_LENGTH:
6774 case XC_INST_SQRT:
6775 dbg_exec("BC_INST_builtin:");
6776 s = zxc_program_builtin(inst);
6777 break;
6778 case XC_INST_NUM:
6779 dbg_exec("XC_INST_NUM:");
6780 r.t = XC_RESULT_CONSTANT;
6781 r.d.id.idx = xc_program_index(code, &ip->inst_idx);
6782 bc_vec_push(&G.prog.results, &r);
6783 break;
6784 case XC_INST_POP:
6785 dbg_exec("XC_INST_POP:");
6786 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6787 s = bc_error_stack_has_too_few_elements();
6788 else
6789 bc_vec_pop(&G.prog.results);
6790 break;
6791 case XC_INST_PRINT:
6792 case XC_INST_PRINT_POP:
6793 case XC_INST_PRINT_STR:
6794 dbg_exec("XC_INST_PRINTxyz(%d):", inst - XC_INST_PRINT);
6795 s = zxc_program_print(inst, 0);
6796 break;
6797 case XC_INST_STR:
6798 dbg_exec("XC_INST_STR:");
6799 r.t = XC_RESULT_STR;
6800 r.d.id.idx = xc_program_index(code, &ip->inst_idx);
6801 bc_vec_push(&G.prog.results, &r);
6802 break;
6803 case XC_INST_POWER:
6804 case XC_INST_MULTIPLY:
6805 case XC_INST_DIVIDE:
6806 case XC_INST_MODULUS:
6807 case XC_INST_PLUS:
6808 case XC_INST_MINUS:
6809 dbg_exec("BC_INST_binaryop:");
6810 s = zxc_program_op(inst);
6811 break;
6812 case XC_INST_BOOL_NOT: {
6813 BcNum *num;
6814 dbg_exec("XC_INST_BOOL_NOT:");
6815 s = zxc_program_prep(&ptr, &num);
6816 if (s) RETURN_STATUS(s);
6817 bc_num_init_DEF_SIZE(&r.d.n);
6818 if (bc_num_cmp(num, &G.prog.zero) == 0)
6819 bc_num_one(&r.d.n);
6820
6821 xc_program_retire(&r, XC_RESULT_TEMP);
6822 break;
6823 }
6824 case XC_INST_NEG:
6825 dbg_exec("XC_INST_NEG:");
6826 s = zxc_program_negate();
6827 break;
6828#if ENABLE_BC
6829 case BC_INST_ASSIGN_POWER:
6830 case BC_INST_ASSIGN_MULTIPLY:
6831 case BC_INST_ASSIGN_DIVIDE:
6832 case BC_INST_ASSIGN_MODULUS:
6833 case BC_INST_ASSIGN_PLUS:
6834 case BC_INST_ASSIGN_MINUS:
6835#endif
6836 case XC_INST_ASSIGN:
6837 dbg_exec("BC_INST_ASSIGNxyz:");
6838 s = zxc_program_assign(inst);
6839 break;
6840#if ENABLE_DC
6841 case DC_INST_POP_EXEC:
6842 dbg_exec("DC_INST_POP_EXEC:");
6843 bc_vec_pop(&G.prog.exestack);
6844 goto read_updated_ip;
6845 case DC_INST_MODEXP:
6846 dbg_exec("DC_INST_MODEXP:");
6847 s = zdc_program_modexp();
6848 break;
6849 case DC_INST_DIVMOD:
6850 dbg_exec("DC_INST_DIVMOD:");
6851 s = zdc_program_divmod();
6852 break;
6853 case DC_INST_EXECUTE:
6854 case DC_INST_EXEC_COND:
6855 dbg_exec("DC_INST_EXEC[_COND]:");
6856 s = zdc_program_execStr(code, &ip->inst_idx, inst == DC_INST_EXEC_COND);
6857 goto read_updated_ip;
6858 case DC_INST_PRINT_STACK: {
6859 size_t idx;
6860 dbg_exec("DC_INST_PRINT_STACK:");
6861 for (idx = 0; idx < G.prog.results.len; ++idx) {
6862 s = zxc_program_print(XC_INST_PRINT, idx);
6863 if (s) break;
6864 }
6865 break;
6866 }
6867 case DC_INST_CLEAR_STACK:
6868 dbg_exec("DC_INST_CLEAR_STACK:");
6869 bc_vec_pop_all(&G.prog.results);
6870 break;
6871 case DC_INST_STACK_LEN:
6872 dbg_exec("DC_INST_STACK_LEN:");
6873 dc_program_stackLen();
6874 break;
6875 case DC_INST_DUPLICATE:
6876 dbg_exec("DC_INST_DUPLICATE:");
6877 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6878 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6879 ptr = bc_vec_top(&G.prog.results);
6880 dc_result_copy(&r, ptr);
6881 bc_vec_push(&G.prog.results, &r);
6882 break;
6883 case DC_INST_SWAP: {
6884 BcResult *ptr2;
6885 dbg_exec("DC_INST_SWAP:");
6886 if (!STACK_HAS_MORE_THAN(&G.prog.results, 1))
6887 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6888 ptr = bc_vec_item_rev(&G.prog.results, 0);
6889 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6890 memcpy(&r, ptr, sizeof(BcResult));
6891 memcpy(ptr, ptr2, sizeof(BcResult));
6892 memcpy(ptr2, &r, sizeof(BcResult));
6893 break;
6894 }
6895 case DC_INST_ASCIIFY:
6896 dbg_exec("DC_INST_ASCIIFY:");
6897 s = zdc_program_asciify();
6898 break;
6899 case DC_INST_PRINT_STREAM:
6900 dbg_exec("DC_INST_PRINT_STREAM:");
6901 s = zdc_program_printStream();
6902 break;
6903 case DC_INST_LOAD:
6904 case DC_INST_PUSH_VAR: {
6905 bool copy = inst == DC_INST_LOAD;
6906 s = zxc_program_pushVar(code, &ip->inst_idx, true, copy);
6907 break;
6908 }
6909 case DC_INST_PUSH_TO_VAR: {
6910 char *name = xc_program_name(code, &ip->inst_idx);
6911 s = zxc_program_popResultAndCopyToVar(name, BC_TYPE_VAR);
6912 free(name);
6913 break;
6914 }
6915 case DC_INST_QUIT:
6916 dbg_exec("DC_INST_QUIT:");
6917 if (G.prog.exestack.len <= 2)
6918 QUIT_OR_RETURN_TO_MAIN;
6919 bc_vec_npop(&G.prog.exestack, 2);
6920 goto read_updated_ip;
6921 case DC_INST_NQUIT:
6922 dbg_exec("DC_INST_NQUIT:");
6923 s = zdc_program_nquit();
6924
6925#endif
6926 read_updated_ip:
6927
6928 ip = bc_vec_top(&G.prog.exestack);
6929 func = xc_program_func(ip->func);
6930 code = func->code.v;
6931 dbg_exec("func:%zd bytes:%zd ip:%zd", ip->func, func->code.len, ip->inst_idx);
6932 }
6933
6934 if (s || G_interrupt) {
6935 xc_program_reset();
6936 RETURN_STATUS(s);
6937 }
6938
6939 fflush_and_check();
6940 }
6941
6942 RETURN_STATUS(BC_STATUS_SUCCESS);
6943}
6944#define zxc_program_exec(...) (zxc_program_exec(__VA_ARGS__) COMMA_SUCCESS)
6945
6946static BC_STATUS zxc_vm_process(const char *text)
6947{
6948 BcStatus s;
6949
6950 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
6951 s = zxc_parse_text_init(text);
6952 if (s) RETURN_STATUS(s);
6953
6954 while (G.prs.lex != XC_LEX_EOF) {
6955 BcInstPtr *ip;
6956 BcFunc *f;
6957
6958 dbg_lex("%s:%d G.prs.lex:%d, parsing...", __func__, __LINE__, G.prs.lex);
6959 if (IS_BC) {
6960#if ENABLE_BC
6961 s = zbc_parse_stmt_or_funcdef();
6962 if (s) goto err;
6963
6964
6965
6966 if (G.prs.lex != BC_LEX_SCOLON
6967 && G.prs.lex != XC_LEX_NLINE
6968 && G.prs.lex != XC_LEX_EOF
6969 ) {
6970 bc_error_at("bad statement terminator");
6971 goto err;
6972 }
6973
6974
6975#endif
6976 } else {
6977#if ENABLE_DC
6978 s = zdc_parse_expr();
6979#endif
6980 }
6981 if (s || G_interrupt) {
6982 err:
6983 xc_parse_reset();
6984 RETURN_STATUS(BC_STATUS_FAILURE);
6985 }
6986
6987 dbg_lex("%s:%d executing...", __func__, __LINE__);
6988 s = zxc_program_exec();
6989 if (s) {
6990 xc_program_reset();
6991 break;
6992 }
6993
6994 ip = (void*)G.prog.exestack.v;
6995#if SANITY_CHECKS
6996 if (G.prog.exestack.len != 1)
6997 bb_simple_error_msg_and_die("BUG:call stack");
6998 if (ip->func != BC_PROG_MAIN)
6999 bb_simple_error_msg_and_die("BUG:not MAIN");
7000#endif
7001 f = xc_program_func_BC_PROG_MAIN();
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012 if (IS_BC) {
7013#if SANITY_CHECKS
7014 if (G.prog.results.len != 0)
7015 bb_simple_error_msg_and_die("BUG:data stack");
7016#endif
7017 IF_BC(bc_vec_pop_all(&f->strs);)
7018 IF_BC(bc_vec_pop_all(&f->consts);)
7019
7020 s = zxc_lex_next();
7021 if (s) goto err;
7022 } else {
7023 if (G.prog.results.len == 0
7024 && G.prog.vars.len == 0
7025 ) {
7026
7027
7028
7029
7030
7031 IF_DC(bc_vec_pop_all(&G.prog.strs);)
7032 IF_DC(bc_vec_pop_all(&G.prog.consts);)
7033 }
7034
7035
7036
7037
7038 }
7039
7040 bc_vec_pop_all(&f->code);
7041 ip->inst_idx = 0;
7042 }
7043
7044 dbg_lex_done("%s:%d done", __func__, __LINE__);
7045 RETURN_STATUS(s);
7046}
7047#define zxc_vm_process(...) (zxc_vm_process(__VA_ARGS__) COMMA_SUCCESS)
7048
7049static BC_STATUS zxc_vm_execute_FILE(FILE *fp, const char *filename)
7050{
7051
7052
7053
7054 BcStatus s;
7055
7056 G.prs.lex_filename = filename;
7057 G.prs.lex_input_fp = fp;
7058 G.err_line = G.prs.lex_line = 1;
7059 dbg_lex("p->lex_line reset to 1");
7060
7061 do {
7062 s = zxc_vm_process("");
7063
7064
7065
7066
7067 } while (G.prs.lex_input_fp == stdin);
7068 G.prs.lex_filename = NULL;
7069 RETURN_STATUS(s);
7070}
7071#define zxc_vm_execute_FILE(...) (zxc_vm_execute_FILE(__VA_ARGS__) COMMA_SUCCESS)
7072
7073static BC_STATUS zxc_vm_file(const char *file)
7074{
7075 BcStatus s;
7076 FILE *fp;
7077
7078 fp = xfopen_for_read(file);
7079 s = zxc_vm_execute_FILE(fp, file);
7080 fclose(fp);
7081
7082 RETURN_STATUS(s);
7083}
7084#define zxc_vm_file(...) (zxc_vm_file(__VA_ARGS__) COMMA_SUCCESS)
7085
7086#if ENABLE_BC
7087static void bc_vm_info(void)
7088{
7089 printf("%s "BB_VER"\n"
7090 "Adapted from https://github.com/gavinhoward/bc\n"
7091 "Original code (c) 2018 Gavin D. Howard and contributors\n"
7092 , applet_name);
7093}
7094
7095static void bc_args(char **argv)
7096{
7097 unsigned opts;
7098 int i;
7099
7100 GETOPT_RESET();
7101#if ENABLE_FEATURE_BC_LONG_OPTIONS
7102 opts = option_mask32 |= getopt32long(argv, "wvsqli",
7103 "warn\0" No_argument "w"
7104 "version\0" No_argument "v"
7105 "standard\0" No_argument "s"
7106 "quiet\0" No_argument "q"
7107 "mathlib\0" No_argument "l"
7108 "interactive\0" No_argument "i"
7109 );
7110#else
7111 opts = option_mask32 |= getopt32(argv, "wvsqli");
7112#endif
7113 if (getenv("POSIXLY_CORRECT"))
7114 option_mask32 |= BC_FLAG_S;
7115
7116 if (opts & BC_FLAG_V) {
7117 bc_vm_info();
7118 exit(0);
7119 }
7120
7121 for (i = optind; argv[i]; ++i)
7122 bc_vec_push(&G.files, argv + i);
7123}
7124
7125static void bc_vm_envArgs(void)
7126{
7127 BcVec v;
7128 char *buf;
7129 char *env_args = getenv("BC_ENV_ARGS");
7130
7131 if (!env_args) return;
7132
7133 G.env_args = xstrdup(env_args);
7134 buf = G.env_args;
7135
7136 bc_vec_init(&v, sizeof(char *), NULL);
7137
7138 while (*(buf = skip_whitespace(buf)) != '\0') {
7139 bc_vec_push(&v, &buf);
7140 buf = skip_non_whitespace(buf);
7141 if (!*buf)
7142 break;
7143 *buf++ = '\0';
7144 }
7145
7146
7147 if (sizeof(int) == sizeof(char*)) {
7148 bc_vec_push(&v, &const_int_0);
7149 } else {
7150 static char *const nullptr = NULL;
7151 bc_vec_push(&v, &nullptr);
7152 }
7153 bc_args(((char **)v.v) - 1);
7154
7155 bc_vec_free(&v);
7156}
7157
7158static const char bc_lib[] ALIGN1 = {
7159 "scale=20"
7160"\n" "define e(x){"
7161"\n" "auto b,s,n,r,d,i,p,f,v"
7162
7163
7164
7165
7166
7167
7168"\n" "b=ibase"
7169"\n" "ibase=A"
7170"\n" "if(x<0){"
7171"\n" "n=1"
7172"\n" "x=-x"
7173"\n" "}"
7174"\n" "s=scale"
7175"\n" "r=6+s+.44*x"
7176"\n" "scale=scale(x)+1"
7177"\n" "while(x>1){"
7178"\n" "d+=1"
7179"\n" "x/=2"
7180"\n" "scale+=1"
7181"\n" "}"
7182"\n" "scale=r"
7183"\n" "r=x+1"
7184"\n" "p=x"
7185"\n" "f=v=1"
7186"\n" "for(i=2;v;++i){"
7187"\n" "p*=x"
7188"\n" "f*=i"
7189"\n" "v=p/f"
7190"\n" "r+=v"
7191"\n" "}"
7192"\n" "while(d--)r*=r"
7193"\n" "scale=s"
7194"\n" "ibase=b"
7195"\n" "if(n)return(1/r)"
7196"\n" "return(r/1)"
7197"\n" "}"
7198"\n" "define l(x){"
7199"\n" "auto b,s,r,p,a,q,i,v"
7200"\n" "b=ibase"
7201"\n" "ibase=A"
7202"\n" "if(x<=0){"
7203"\n" "r=(1-10^scale)/1"
7204"\n" "ibase=b"
7205"\n" "return(r)"
7206"\n" "}"
7207"\n" "s=scale"
7208"\n" "scale+=6"
7209"\n" "p=2"
7210"\n" "while(x>=2){"
7211"\n" "p*=2"
7212"\n" "x=sqrt(x)"
7213"\n" "}"
7214"\n" "while(x<=.5){"
7215"\n" "p*=2"
7216"\n" "x=sqrt(x)"
7217"\n" "}"
7218"\n" "r=a=(x-1)/(x+1)"
7219"\n" "q=a*a"
7220"\n" "v=1"
7221"\n" "for(i=3;v;i+=2){"
7222"\n" "a*=q"
7223"\n" "v=a/i"
7224"\n" "r+=v"
7225"\n" "}"
7226"\n" "r*=p"
7227"\n" "scale=s"
7228"\n" "ibase=b"
7229"\n" "return(r/1)"
7230"\n" "}"
7231"\n" "define s(x){"
7232"\n" "auto b,s,r,a,q,i"
7233"\n" "if(x<0)return(-s(-x))"
7234"\n" "b=ibase"
7235"\n" "ibase=A"
7236"\n" "s=scale"
7237"\n" "scale=1.1*s+2"
7238"\n" "a=a(1)"
7239"\n" "scale=0"
7240"\n" "q=(x/a+2)/4"
7241"\n" "x-=4*q*a"
7242"\n" "if(q%2)x=-x"
7243"\n" "scale=s+2"
7244"\n" "r=a=x"
7245"\n" "q=-x*x"
7246"\n" "for(i=3;a;i+=2){"
7247"\n" "a*=q/(i*(i-1))"
7248"\n" "r+=a"
7249"\n" "}"
7250"\n" "scale=s"
7251"\n" "ibase=b"
7252"\n" "return(r/1)"
7253"\n" "}"
7254"\n" "define c(x){"
7255"\n" "auto b,s"
7256"\n" "b=ibase"
7257"\n" "ibase=A"
7258"\n" "s=scale"
7259"\n" "scale*=1.2"
7260"\n" "x=s(2*a(1)+x)"
7261"\n" "scale=s"
7262"\n" "ibase=b"
7263"\n" "return(x/1)"
7264"\n" "}"
7265"\n" "define a(x){"
7266"\n" "auto b,s,r,n,a,m,t,f,i,u"
7267"\n" "b=ibase"
7268"\n" "ibase=A"
7269"\n" "n=1"
7270"\n" "if(x<0){"
7271"\n" "n=-1"
7272"\n" "x=-x"
7273"\n" "}"
7274"\n" "if(scale<65){"
7275"\n" "if(x==1)return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7276"\n" "if(x==.2)return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7277"\n" "}"
7278"\n" "s=scale"
7279"\n" "if(x>.2){"
7280"\n" "scale+=5"
7281"\n" "a=a(.2)"
7282"\n" "}"
7283"\n" "scale=s+3"
7284"\n" "while(x>.2){"
7285"\n" "m+=1"
7286"\n" "x=(x-.2)/(1+.2*x)"
7287"\n" "}"
7288"\n" "r=u=x"
7289"\n" "f=-x*x"
7290"\n" "t=1"
7291"\n" "for(i=3;t;i+=2){"
7292"\n" "u*=f"
7293"\n" "t=u/i"
7294"\n" "r+=t"
7295"\n" "}"
7296"\n" "scale=s"
7297"\n" "ibase=b"
7298"\n" "return((m*a+r)/n)"
7299"\n" "}"
7300"\n" "define j(n,x){"
7301"\n" "auto b,s,o,a,i,v,f"
7302"\n" "b=ibase"
7303"\n" "ibase=A"
7304"\n" "s=scale"
7305"\n" "scale=0"
7306"\n" "n/=1"
7307"\n" "if(n<0){"
7308"\n" "n=-n"
7309"\n" "o=n%2"
7310"\n" "}"
7311"\n" "a=1"
7312"\n" "for(i=2;i<=n;++i)a*=i"
7313"\n" "scale=1.5*s"
7314"\n" "a=(x^n)/2^n/a"
7315"\n" "r=v=1"
7316"\n" "f=-x*x/4"
7317"\n" "scale+=length(a)-scale(a)"
7318"\n" "for(i=1;v;++i){"
7319"\n" "v=v*f/i/(n+i)"
7320"\n" "r+=v"
7321"\n" "}"
7322"\n" "scale=s"
7323"\n" "ibase=b"
7324"\n" "if(o)a=-a"
7325"\n" "return(a*r/1)"
7326"\n" "}"
7327};
7328#endif
7329
7330static BC_STATUS zxc_vm_exec(void)
7331{
7332 char **fname;
7333 BcStatus s;
7334 size_t i;
7335
7336#if ENABLE_BC
7337 if (option_mask32 & BC_FLAG_L) {
7338
7339
7340# define DEBUG_LIB 0
7341 s = zxc_vm_process(bc_lib);
7342 if (DEBUG_LIB && s) RETURN_STATUS(s);
7343 }
7344#endif
7345
7346 s = BC_STATUS_SUCCESS;
7347 fname = (void*)G.files.v;
7348 for (i = 0; i < G.files.len; i++) {
7349 s = zxc_vm_file(*fname++);
7350 if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin && s) {
7351
7352
7353
7354
7355 RETURN_STATUS(s);
7356 }
7357 }
7358
7359 if (IS_BC || (option_mask32 & BC_FLAG_I))
7360 s = zxc_vm_execute_FILE(stdin, NULL);
7361
7362 RETURN_STATUS(s);
7363}
7364#define zxc_vm_exec(...) (zxc_vm_exec(__VA_ARGS__) COMMA_SUCCESS)
7365
7366#if ENABLE_FEATURE_CLEAN_UP
7367static void xc_program_free(void)
7368{
7369 bc_vec_free(&G.prog.fns);
7370 IF_BC(bc_vec_free(&G.prog.fn_map);)
7371 bc_vec_free(&G.prog.vars);
7372 bc_vec_free(&G.prog.var_map);
7373 bc_vec_free(&G.prog.arrs);
7374 bc_vec_free(&G.prog.arr_map);
7375 IF_DC(bc_vec_free(&G.prog.strs);)
7376 IF_DC(bc_vec_free(&G.prog.consts);)
7377 bc_vec_free(&G.prog.results);
7378 bc_vec_free(&G.prog.exestack);
7379 IF_BC(bc_num_free(&G.prog.last);)
7380
7381 IF_BC(bc_num_free(&G.prog.one);)
7382 bc_vec_free(&G.input_buffer);
7383}
7384#endif
7385
7386static void xc_program_init(void)
7387{
7388 BcInstPtr ip;
7389
7390
7391 memset(&ip, 0, sizeof(BcInstPtr));
7392
7393
7394 G.prog.ib_t = 10;
7395 G.prog.ob_t = 10;
7396
7397 IF_BC(bc_num_init_DEF_SIZE(&G.prog.last);)
7398
7399
7400
7401
7402
7403 IF_BC(bc_num_init_DEF_SIZE(&G.prog.one);)
7404 IF_BC(bc_num_one(&G.prog.one);)
7405
7406 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7407 IF_BC(bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);)
7408
7409 if (IS_BC) {
7410
7411
7412 IF_BC(bc_program_addFunc(xstrdup("")));
7413 IF_BC(bc_program_addFunc(xstrdup("1")));
7414 } else {
7415
7416 xc_program_add_fn();
7417 xc_program_add_fn();
7418 }
7419
7420 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7421 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7422
7423 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7424 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7425
7426 IF_DC(bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);)
7427 IF_DC(bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);)
7428 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7429 bc_vec_init(&G.prog.exestack, sizeof(BcInstPtr), NULL);
7430 bc_vec_push(&G.prog.exestack, &ip);
7431
7432 bc_char_vec_init(&G.input_buffer);
7433}
7434
7435static unsigned xc_vm_envLen(const char *var)
7436{
7437 char *lenv;
7438 unsigned len;
7439
7440 lenv = getenv(var);
7441 len = BC_NUM_PRINT_WIDTH;
7442 if (lenv) {
7443 len = bb_strtou(lenv, NULL, 10);
7444 if (len == 0 || len > INT_MAX)
7445 len = INT_MAX;
7446 if (errno)
7447 len = BC_NUM_PRINT_WIDTH;
7448 }
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460 if (IS_BC)
7461 len--;
7462
7463 if (len < 2)
7464 len = IS_BC ? BC_NUM_PRINT_WIDTH - 1 : BC_NUM_PRINT_WIDTH;
7465
7466 return len;
7467}
7468
7469static int xc_vm_init(const char *env_len)
7470{
7471 G.prog.len = xc_vm_envLen(env_len);
7472 bc_vec_init(&G.files, sizeof(char *), NULL);
7473
7474 xc_program_init();
7475 IF_BC(if (IS_BC) bc_vm_envArgs();)
7476 xc_parse_create(BC_PROG_MAIN);
7477
7478
7479
7480 if (isatty(0)) {
7481#if ENABLE_FEATURE_BC_INTERACTIVE
7482 G_ttyin = 1;
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7495
7496
7497
7498
7499
7500
7501
7502#endif
7503 return 1;
7504 }
7505 return 0;
7506}
7507
7508static BcStatus xc_vm_run(void)
7509{
7510 BcStatus st = zxc_vm_exec();
7511#if ENABLE_FEATURE_CLEAN_UP
7512 if (G_exiting)
7513 st = EXIT_SUCCESS;
7514
7515 bc_vec_free(&G.files);
7516 xc_program_free();
7517 xc_parse_free();
7518 free(G.env_args);
7519# if ENABLE_FEATURE_EDITING
7520 free_line_input_t(G.line_input_state);
7521# endif
7522 FREE_G();
7523#endif
7524 dbg_exec("exiting with exitcode %d", st);
7525 return st;
7526}
7527
7528#if ENABLE_BC
7529int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7530int bc_main(int argc UNUSED_PARAM, char **argv)
7531{
7532 int is_tty;
7533
7534 INIT_G();
7535
7536 is_tty = xc_vm_init("BC_LINE_LENGTH");
7537
7538 bc_args(argv);
7539
7540 if (is_tty && !(option_mask32 & BC_FLAG_Q))
7541 bc_vm_info();
7542
7543 return xc_vm_run();
7544}
7545#endif
7546
7547#if ENABLE_DC
7548int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7549int dc_main(int argc UNUSED_PARAM, char **argv)
7550{
7551 int noscript;
7552
7553 INIT_G();
7554
7555 xc_vm_init("DC_LINE_LENGTH");
7556
7557
7558 noscript = BC_FLAG_I;
7559 for (;;) {
7560 int n = getopt(argc, argv, "e:f:x");
7561 if (n <= 0)
7562 break;
7563 switch (n) {
7564 case 'e':
7565 noscript = 0;
7566 n = zxc_vm_process(optarg);
7567 if (n) return n;
7568 break;
7569 case 'f':
7570 noscript = 0;
7571 n = zxc_vm_file(optarg);
7572 if (n) return n;
7573 break;
7574 case 'x':
7575 option_mask32 |= DC_FLAG_X;
7576 break;
7577 default:
7578 bb_show_usage();
7579 }
7580 }
7581 argv += optind;
7582
7583 while (*argv) {
7584 noscript = 0;
7585 bc_vec_push(&G.files, argv++);
7586 }
7587
7588 option_mask32 |= noscript;
7589
7590 return xc_vm_run();
7591}
7592#endif
7593
7594#endif
7595