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