"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "bc-1.06.95/bc/bc.y" of archive bc-1.06.95.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /* This file is part of GNU bc.
2
3 Copyright (C) 1991-1994, 1997, 2006 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License , or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to:
17 The Free Software Foundation, Inc.
18 Foundation, Inc. 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301 USA
20
21 You may contact the author by:
22 e-mail: philnelson@acm.org
23 us-mail: Philip A. Nelson
24 Computer Science Department, 9062
25 Western Washington University
26 Bellingham, WA 98226-9062
27
28 *************************************************************************/
29
30 /* bc.y: The grammar for a POSIX compatable bc processor with some
31 extensions to the language. */
32
33 %{
34
35 #include "bcdefs.h"
36 #include "global.h"
37 #include "proto.h"
38
39 /* current function number. */
40 int cur_func = -1;
41
42 /* Expression encoded information -- See comment at expression rules. */
43 #define EX_ASSGN 0
44 #define EX_REG 1
45 #define EX_COMP 2
46 #define EX_PAREN 4
47 #define EX_VOID 8
48 #define EX_EMPTY 16
49
50 %}
51
52 %start program
53
54 %union {
55 char *s_value;
56 char c_value;
57 int i_value;
58 arg_list *a_value;
59 }
60
61 /* Extensions over POSIX bc.
62 a) NAME was LETTER. This grammar allows longer names.
63 Single letter names will still work.
64 b) Relational_expression allowed only one comparison.
65 This grammar has added boolean expressions with
66 && (and) || (or) and ! (not) and allowed all of them in
67 full expressions.
68 c) Added an else to the if.
69 d) Call by variable array parameters
70 e) read() procedure that reads a number under program control from stdin.
71 f) halt statement that halts the the program under program control. It
72 is an executed statement.
73 g) continue statement for for loops.
74 h) optional expressions in the for loop.
75 i) print statement to print multiple numbers per line.
76 j) warranty statement to print an extended warranty notice.
77 j) limits statement to print the processor's limits.
78 */
79
80 %token <i_value> ENDOFLINE AND OR NOT
81 %token <s_value> STRING NAME NUMBER
82 /* '-', '+' are tokens themselves */
83 /* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
84 %token <c_value> ASSIGN_OP
85 /* '==', '<=', '>=', '!=', '<', '>' */
86 %token <s_value> REL_OP
87 /* '++', '--' */
88 %token <c_value> INCR_DECR
89 /* 'define', 'break', 'quit', 'length' */
90 %token <i_value> Define Break Quit Length
91 /* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
92 %token <i_value> Return For If While Sqrt Else
93 /* 'scale', 'ibase', 'obase', 'auto', 'read', 'random' */
94 %token <i_value> Scale Ibase Obase Auto Read Random
95 /* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
96 %token <i_value> Warranty Halt Last Continue Print Limits
97 /* 'history', 'void' */
98 %token <i_value> UNARY_MINUS HistoryVar Void
99
100
101 /* Types of all other things. */
102 %type <i_value> expression return_expression named_expression opt_expression
103 %type <c_value> '+' '-' '*' '/' '%'
104 %type <a_value> opt_parameter_list opt_auto_define_list define_list
105 %type <a_value> opt_argument_list argument_list
106 %type <i_value> program input_item semicolon_list statement_list
107 %type <i_value> statement function statement_or_error required_eol
108 %type <i_value> opt_void
109
110 /* precedence */
111 %left OR
112 %left AND
113 %nonassoc NOT
114 %left REL_OP
115 %right ASSIGN_OP
116 %left '+' '-'
117 %left '*' '/' '%'
118 %right '^'
119 %nonassoc UNARY_MINUS
120 %nonassoc INCR_DECR
121
122 %%
123 program : /* empty */
124 {
125 $$ = 0;
126 if (interactive && !quiet)
127 {
128 show_bc_version ();
129 welcome ();
130 }
131 }
132 | program input_item
133 ;
134 input_item : semicolon_list ENDOFLINE
135 { run_code (); }
136 | function
137 { run_code (); }
138 | error ENDOFLINE
139 {
140 yyerrok;
141 init_gen ();
142 }
143 ;
144 opt_newline : /* empty */
145 | ENDOFLINE
146 { warn ("newline not allowed"); }
147 ;
148 semicolon_list : /* empty */
149 { $$ = 0; }
150 | statement_or_error
151 | semicolon_list ';' statement_or_error
152 | semicolon_list ';'
153 ;
154 statement_list : /* empty */
155 { $$ = 0; }
156 | statement_or_error
157 | statement_list ENDOFLINE
158 | statement_list ENDOFLINE statement_or_error
159 | statement_list ';'
160 | statement_list ';' statement
161 ;
162 statement_or_error : statement
163 | error statement
164 { $$ = $2; }
165 ;
166 statement : Warranty
167 { warranty (""); }
168 | Limits
169 { limits (); }
170 | expression
171 {
172 if ($1 & EX_COMP)
173 warn ("comparison in expression");
174 if ($1 & EX_REG)
175 generate ("W");
176 else
177 generate ("p");
178 }
179 | STRING
180 {
181 $$ = 0;
182 generate ("w");
183 generate ($1);
184 free ($1);
185 }
186 | Break
187 {
188 if (break_label == 0)
189 yyerror ("Break outside a for/while");
190 else
191 {
192 sprintf (genstr, "J%1d:", break_label);
193 generate (genstr);
194 }
195 }
196 | Continue
197 {
198 warn ("Continue statement");
199 if (continue_label == 0)
200 yyerror ("Continue outside a for");
201 else
202 {
203 sprintf (genstr, "J%1d:", continue_label);
204 generate (genstr);
205 }
206 }
207 | Quit
208 { exit (0); }
209 | Halt
210 { generate ("h"); }
211 | Return return_expression
212 { generate ("R"); }
213 | For
214 {
215 $1 = break_label;
216 break_label = next_label++;
217 }
218 '(' opt_expression ';'
219 {
220 if ($4 & EX_COMP)
221 warn ("Comparison in first for expression");
222 if ($4 & EX_VOID)
223 yyerror ("first expression is void");
224 if (!($4 & EX_EMPTY))
225 generate ("p");
226 $4 = next_label++;
227 sprintf (genstr, "N%1d:", $4);
228 generate (genstr);
229 }
230 opt_expression ';'
231 {
232 if ($7 & EX_VOID)
233 yyerror ("second expression is void");
234 if ($7 & EX_EMPTY ) generate ("1");
235 $7 = next_label++;
236 sprintf (genstr, "B%1d:J%1d:", $7, break_label);
237 generate (genstr);
238 $<i_value>$ = continue_label;
239 continue_label = next_label++;
240 sprintf (genstr, "N%1d:", continue_label);
241 generate (genstr);
242 }
243 opt_expression ')'
244 {
245 if ($10 & EX_COMP)
246 warn ("Comparison in third for expression");
247 if ($10 & EX_VOID)
248 yyerror ("third expression is void");
249 if ($10 & EX_EMPTY)
250 sprintf (genstr, "J%1d:N%1d:", $4, $7);
251 else
252 sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
253 generate (genstr);
254 }
255 opt_newline statement
256 {
257 sprintf (genstr, "J%1d:N%1d:",
258 continue_label, break_label);
259 generate (genstr);
260 break_label = $1;
261 continue_label = $<i_value>9;
262 }
263 | If '(' expression ')'
264 {
265 if ($3 & EX_VOID)
266 yyerror ("void expression");
267 $3 = if_label;
268 if_label = next_label++;
269 sprintf (genstr, "Z%1d:", if_label);
270 generate (genstr);
271 }
272 opt_newline statement opt_else
273 {
274 sprintf (genstr, "N%1d:", if_label);
275 generate (genstr);
276 if_label = $3;
277 }
278 | While
279 {
280 $1 = next_label++;
281 sprintf (genstr, "N%1d:", $1);
282 generate (genstr);
283 }
284 '(' expression
285 {
286 if ($4 & EX_VOID)
287 yyerror ("void expression");
288 $4 = break_label;
289 break_label = next_label++;
290 sprintf (genstr, "Z%1d:", break_label);
291 generate (genstr);
292 }
293 ')' opt_newline statement
294 {
295 sprintf (genstr, "J%1d:N%1d:", $1, break_label);
296 generate (genstr);
297 break_label = $4;
298 }
299 | '{' statement_list '}'
300 { $$ = 0; }
301 | Print
302 { warn ("print statement"); }
303 print_list
304 ;
305 print_list : print_element
306 | print_element ',' print_list
307 ;
308 print_element : STRING
309 {
310 generate ("O");
311 generate ($1);
312 free ($1);
313 }
314 | expression
315 {
316 if ($1 & EX_VOID)
317 yyerror ("void expression in print");
318 generate ("P");
319 }
320 ;
321 opt_else : /* nothing */
322 | Else
323 {
324 warn ("else clause in if statement");
325 $1 = next_label++;
326 sprintf (genstr, "J%d:N%1d:", $1, if_label);
327 generate (genstr);
328 if_label = $1;
329 }
330 opt_newline statement
331 ;
332 function : Define opt_void NAME '(' opt_parameter_list ')' opt_newline
333 '{' required_eol opt_auto_define_list
334 { char *params, *autos;
335 /* Check auto list against parameter list? */
336 check_params ($5,$10);
337 params = arg_str ($5);
338 autos = arg_str ($10);
339 set_genstr_size (30 + strlen (params)
340 + strlen (autos));
341 cur_func = lookup($3,FUNCTDEF);
342 sprintf (genstr, "F%d,%s.%s[", cur_func, params,
343 autos);
344 generate (genstr);
345 functions[cur_func].f_void = $2;
346 free_args ($5);
347 free_args ($10);
348 $1 = next_label;
349 next_label = 1;
350 }
351 statement_list /* ENDOFLINE */ '}'
352 {
353 generate ("0R]");
354 next_label = $1;
355 cur_func = -1;
356 }
357 ;
358 opt_void : /* empty */
359 { $$ = 0; }
360 | Void
361 {
362 $$ = 1;
363 warn ("void functions");
364 }
365 ;
366 opt_parameter_list : /* empty */
367 { $$ = NULL; }
368 | define_list
369 ;
370 opt_auto_define_list : /* empty */
371 { $$ = NULL; }
372 | Auto define_list ENDOFLINE
373 { $$ = $2; }
374 | Auto define_list ';'
375 { $$ = $2; }
376 ;
377 define_list : NAME
378 { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);}
379 | NAME '[' ']'
380 { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
381 | '*' NAME '[' ']'
382 { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE);
383 warn ("Call by variable arrays");
384 }
385 | '&' NAME '[' ']'
386 { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE);
387 warn ("Call by variable arrays");
388 }
389 | define_list ',' NAME
390 { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
391 | define_list ',' NAME '[' ']'
392 { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
393 | define_list ',' '*' NAME '[' ']'
394 { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE);
395 warn ("Call by variable arrays");
396 }
397 | define_list ',' '&' NAME '[' ']'
398 { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE);
399 warn ("Call by variable arrays");
400 }
401 ;
402 opt_argument_list : /* empty */
403 { $$ = NULL; }
404 | argument_list
405 ;
406 argument_list : expression
407 {
408 if ($1 & EX_COMP)
409 warn ("comparison in argument");
410 if ($1 & EX_VOID)
411 yyerror ("void argument");
412 $$ = nextarg (NULL,0,FALSE);
413 }
414 | NAME '[' ']'
415 {
416 sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
417 generate (genstr);
418 $$ = nextarg (NULL,1,FALSE);
419 }
420 | argument_list ',' expression
421 {
422 if ($3 & EX_COMP)
423 warn ("comparison in argument");
424 if ($3 & EX_VOID)
425 yyerror ("void argument");
426 $$ = nextarg ($1,0,FALSE);
427 }
428 | argument_list ',' NAME '[' ']'
429 {
430 sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
431 generate (genstr);
432 $$ = nextarg ($1,1,FALSE);
433 }
434 ;
435
436 /* Expression lval meanings! (Bits mean something!) (See defines above)
437 * 0 => Top op is assignment.
438 * 1 => Top op is not assignment.
439 * 2 => Comparison is somewhere in expression.
440 * 4 => Expression is in parenthesis.
441 * 8 => Expression is void!
442 * 16 => Empty optional expression.
443 */
444
445 opt_expression : /* empty */
446 {
447 $$ = EX_EMPTY;
448 warn ("Missing expression in for statement");
449 }
450 | expression
451 ;
452 return_expression : /* empty */
453 {
454 $$ = 0;
455 generate ("0");
456 if (cur_func == -1)
457 yyerror("Return outside of a function.");
458 }
459 | expression
460 {
461 if ($1 & EX_COMP)
462 warn ("comparison in return expresion");
463 if (!($1 & EX_PAREN))
464 warn ("return expression requires parenthesis");
465 if ($1 & EX_VOID)
466 yyerror("return requires non-void expression");
467 if (cur_func == -1)
468 yyerror("Return outside of a function.");
469 else if (functions[cur_func].f_void)
470 yyerror("Return expression in a void function.");
471 }
472 ;
473 expression : named_expression ASSIGN_OP
474 {
475 if ($2 != '=')
476 {
477 if ($1 < 0)
478 sprintf (genstr, "DL%d:", -$1);
479 else
480 sprintf (genstr, "l%d:", $1);
481 generate (genstr);
482 }
483 }
484 expression
485 {
486 if ($4 & EX_ASSGN)
487 warn("comparison in assignment");
488 if ($4 & EX_VOID)
489 yyerror("Assignment of a void expression");
490 if ($2 != '=')
491 {
492 sprintf (genstr, "%c", $2);
493 generate (genstr);
494 }
495 if ($1 < 0)
496 sprintf (genstr, "S%d:", -$1);
497 else
498 sprintf (genstr, "s%d:", $1);
499 generate (genstr);
500 $$ = EX_ASSGN;
501 }
502 | expression AND
503 {
504 warn("&& operator");
505 $2 = next_label++;
506 sprintf (genstr, "DZ%d:p", $2);
507 generate (genstr);
508 }
509 expression
510 {
511 if (($1 & EX_VOID) || ($4 & EX_VOID))
512 yyerror ("void expression with &&");
513 sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
514 generate (genstr);
515 $$ = ($1 | $4) & ~EX_PAREN;
516 }
517 | expression OR
518 {
519 warn("|| operator");
520 $2 = next_label++;
521 sprintf (genstr, "B%d:", $2);
522 generate (genstr);
523 }
524 expression
525 {
526 int tmplab;
527 if (($1 & EX_VOID) || ($4 & EX_VOID))
528 yyerror ("void expression with ||");
529 tmplab = next_label++;
530 sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
531 $2, tmplab, $2, tmplab);
532 generate (genstr);
533 $$ = ($1 | $4) & ~EX_PAREN;
534 }
535 | NOT expression
536 {
537 if ($2 & EX_VOID)
538 yyerror ("void expression with !");
539 $$ = $2 & ~EX_PAREN;
540 warn("! operator");
541 generate ("!");
542 }
543 | expression REL_OP expression
544 {
545 if (($1 & EX_VOID) || ($3 & EX_VOID))
546 yyerror ("void expression with comparison");
547 $$ = EX_REG | EX_COMP;
548 switch (*($2))
549 {
550 case '=':
551 generate ("=");
552 break;
553
554 case '!':
555 generate ("#");
556 break;
557
558 case '<':
559 if ($2[1] == '=')
560 generate ("{");
561 else
562 generate ("<");
563 break;
564
565 case '>':
566 if ($2[1] == '=')
567 generate ("}");
568 else
569 generate (">");
570 break;
571 }
572 }
573 | expression '+' expression
574 {
575 if (($1 & EX_VOID) || ($3 & EX_VOID))
576 yyerror ("void expression with +");
577 generate ("+");
578 $$ = ($1 | $3) & ~EX_PAREN;
579 }
580 | expression '-' expression
581 {
582 if (($1 & EX_VOID) || ($3 & EX_VOID))
583 yyerror ("void expression with -");
584 generate ("-");
585 $$ = ($1 | $3) & ~EX_PAREN;
586 }
587 | expression '*' expression
588 {
589 if (($1 & EX_VOID) || ($3 & EX_VOID))
590 yyerror ("void expression with *");
591 generate ("*");
592 $$ = ($1 | $3) & ~EX_PAREN;
593 }
594 | expression '/' expression
595 {
596 if (($1 & EX_VOID) || ($3 & EX_VOID))
597 yyerror ("void expression with /");
598 generate ("/");
599 $$ = ($1 | $3) & ~EX_PAREN;
600 }
601 | expression '%' expression
602 {
603 if (($1 & EX_VOID) || ($3 & EX_VOID))
604 yyerror ("void expression with %");
605 generate ("%");
606 $$ = ($1 | $3) & ~EX_PAREN;
607 }
608 | expression '^' expression
609 {
610 if (($1 & EX_VOID) || ($3 & EX_VOID))
611 yyerror ("void expression with ^");
612 generate ("^");
613 $$ = ($1 | $3) & ~EX_PAREN;
614 }
615 | '-' expression %prec UNARY_MINUS
616 {
617 if ($2 & EX_VOID)
618 yyerror ("void expression with unary -");
619 generate ("n");
620 $$ = $2 & ~EX_PAREN;
621 }
622 | named_expression
623 {
624 $$ = EX_REG;
625 if ($1 < 0)
626 sprintf (genstr, "L%d:", -$1);
627 else
628 sprintf (genstr, "l%d:", $1);
629 generate (genstr);
630 }
631 | NUMBER
632 {
633 int len = strlen($1);
634 $$ = EX_REG;
635 if (len == 1 && *$1 == '0')
636 generate ("0");
637 else if (len == 1 && *$1 == '1')
638 generate ("1");
639 else
640 {
641 generate ("K");
642 generate ($1);
643 generate (":");
644 }
645 free ($1);
646 }
647 | '(' expression ')'
648 {
649 if ($2 & EX_VOID)
650 yyerror ("void expression in parenthesis");
651 $$ = $2 | EX_REG | EX_PAREN;
652 }
653 | NAME '(' opt_argument_list ')'
654 { int fn;
655 fn = lookup ($1,FUNCT);
656 if (functions[fn].f_void)
657 $$ = EX_VOID;
658 else
659 $$ = EX_REG;
660 if ($3 != NULL)
661 { char *params = call_str ($3);
662 set_genstr_size (20 + strlen (params));
663 sprintf (genstr, "C%d,%s:", fn, params);
664 free_args ($3);
665 }
666 else
667 {
668 sprintf (genstr, "C%d:", fn);
669 }
670 generate (genstr);
671 }
672 | INCR_DECR named_expression
673 {
674 $$ = EX_REG;
675 if ($2 < 0)
676 {
677 if ($1 == '+')
678 sprintf (genstr, "DA%d:L%d:", -$2, -$2);
679 else
680 sprintf (genstr, "DM%d:L%d:", -$2, -$2);
681 }
682 else
683 {
684 if ($1 == '+')
685 sprintf (genstr, "i%d:l%d:", $2, $2);
686 else
687 sprintf (genstr, "d%d:l%d:", $2, $2);
688 }
689 generate (genstr);
690 }
691 | named_expression INCR_DECR
692 {
693 $$ = EX_REG;
694 if ($1 < 0)
695 {
696 sprintf (genstr, "DL%d:x", -$1);
697 generate (genstr);
698 if ($2 == '+')
699 sprintf (genstr, "A%d:", -$1);
700 else
701 sprintf (genstr, "M%d:", -$1);
702 }
703 else
704 {
705 sprintf (genstr, "l%d:", $1);
706 generate (genstr);
707 if ($2 == '+')
708 sprintf (genstr, "i%d:", $1);
709 else
710 sprintf (genstr, "d%d:", $1);
711 }
712 generate (genstr);
713 }
714 | Length '(' expression ')'
715 {
716 if ($3 & EX_VOID)
717 yyerror ("void expression in length()");
718 generate ("cL");
719 $$ = EX_REG;
720 }
721 | Sqrt '(' expression ')'
722 {
723 if ($3 & EX_VOID)
724 yyerror ("void expression in sqrt()");
725 generate ("cR");
726 $$ = EX_REG;
727 }
728 | Scale '(' expression ')'
729 {
730 if ($3 & EX_VOID)
731 yyerror ("void expression in scale()");
732 generate ("cS");
733 $$ = EX_REG;
734 }
735 | Read '(' ')'
736 {
737 warn ("read function");
738 generate ("cI");
739 $$ = EX_REG;
740 }
741 | Random '(' ')'
742 {
743 warn ("random function");
744 generate ("cX");
745 $$ = EX_REG;
746 }
747 ;
748 named_expression : NAME
749 { $$ = lookup($1,SIMPLE); }
750 | NAME '[' expression ']'
751 {
752 if ($3 & EX_VOID)
753 yyerror("void expression as subscript");
754 if ($3 & EX_COMP)
755 warn("comparison in subscript");
756 $$ = lookup($1,ARRAY);
757 }
758 | Ibase
759 { $$ = 0; }
760 | Obase
761 { $$ = 1; }
762 | Scale
763 { $$ = 2; }
764 | HistoryVar
765 { $$ = 3;
766 warn ("History variable");
767 }
768 | Last
769 { $$ = 4;
770 warn ("Last variable");
771 }
772 ;
773
774
775 required_eol : { warn ("End of line required"); }
776 | ENDOFLINE
777 | required_eol ENDOFLINE
778 { warn ("Too many end of lines"); }
779 ;
780
781 %%
782