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