2 /* bc.y: The grammar for a POSIX compatable bc processor with some
3 extensions to the language. */
5 /* This file is part of GNU bc.
6 Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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.
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.
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
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
31 *************************************************************************/
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
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.
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
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
84 %token <i_value> UNARY_MINUS HistoryVar
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
103 %nonassoc UNARY_MINUS
107 program : /* empty */
110 if (interactive && !quiet)
118 input_item : semicolon_list ENDOFLINE
128 opt_newline : /* empty */
130 { warn ("newline not allowed"); }
132 semicolon_list : /* empty */
135 | semicolon_list ';' statement_or_error
138 statement_list : /* empty */
141 | statement_list ENDOFLINE
142 | statement_list ENDOFLINE statement_or_error
144 | statement_list ';' statement
146 statement_or_error : statement
157 warn ("comparison in expression");
172 if (break_label == 0)
173 yyerror ("Break outside a for/while");
176 sprintf (genstr, "J%1d:", break_label);
182 warn ("Continue statement");
183 if (continue_label == 0)
184 yyerror ("Continue outside a for");
187 sprintf (genstr, "J%1d:", continue_label);
195 | Return return_expression
200 break_label = next_label++;
202 '(' opt_expression ';'
205 warn ("Comparison in first for expression");
209 sprintf (genstr, "N%1d:", $4);
214 if ($7 < 0) generate ("1");
216 sprintf (genstr, "B%1d:J%1d:", $7, break_label);
218 $<i_value>$ = continue_label;
219 continue_label = next_label++;
220 sprintf (genstr, "N%1d:", continue_label);
226 warn ("Comparison in third for expression");
228 sprintf (genstr, "J%1d:N%1d:", $4, $7);
230 sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
233 opt_newline statement
235 sprintf (genstr, "J%1d:N%1d:",
236 continue_label, break_label);
239 continue_label = $<i_value>9;
241 | If '(' expression ')'
244 if_label = next_label++;
245 sprintf (genstr, "Z%1d:", if_label);
248 opt_newline statement opt_else
250 sprintf (genstr, "N%1d:", if_label);
257 sprintf (genstr, "N%1d:", $1);
263 break_label = next_label++;
264 sprintf (genstr, "Z%1d:", break_label);
267 ')' opt_newline statement
269 sprintf (genstr, "J%1d:N%1d:", $1, break_label);
273 | '{' statement_list '}'
276 { warn ("print statement"); }
279 print_list : print_element
280 | print_element ',' print_list
282 print_element : STRING
291 opt_else : /* nothing */
294 warn ("else clause in if statement");
296 sprintf (genstr, "J%d:N%1d:", $1, if_label);
300 opt_newline statement
301 function : Define NAME '(' opt_parameter_list ')' opt_newline
302 '{' required_eol opt_auto_define_list
304 /* Check auto list against parameter list? */
305 check_params ($4,$9);
306 sprintf (genstr, "F%d,%s.%s[",
308 arg_str ($4), arg_str ($9));
315 statement_list /* ENDOFLINE */ '}'
321 opt_parameter_list : /* empty */
325 opt_auto_define_list : /* empty */
327 | Auto define_list ENDOFLINE
329 | Auto define_list ';'
333 { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);}
335 { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
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); }
345 opt_argument_list : /* empty */
349 argument_list : expression
351 if ($1 & 2) warn ("comparison in argument");
352 $$ = nextarg (NULL,0,FALSE);
356 sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
358 $$ = nextarg (NULL,1,FALSE);
360 | argument_list ',' expression
362 if ($3 & 2) warn ("comparison in argument");
363 $$ = nextarg ($1,0,FALSE);
365 | argument_list ',' NAME '[' ']'
367 sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
369 $$ = nextarg ($1,1,FALSE);
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.
381 opt_expression : /* empty */
384 warn ("Missing expression in for statement");
388 return_expression : /* empty */
396 warn ("comparison in return expresion");
398 warn ("return expression requires parenthesis");
401 expression : named_expression ASSIGN_OP
406 sprintf (genstr, "DL%d:", -$1);
408 sprintf (genstr, "l%d:", $1);
414 if ($4 & 2) warn("comparison in assignment");
417 sprintf (genstr, "%c", $2);
421 sprintf (genstr, "S%d:", -$1);
423 sprintf (genstr, "s%d:", $1);
432 sprintf (genstr, "DZ%d:p", $2);
437 sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
445 sprintf (genstr, "B%d:", $2);
451 tmplab = next_label++;
452 sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
453 $2, tmplab, $2, tmplab);
463 | expression REL_OP expression
491 | expression '+' expression
496 | expression '-' expression
501 | expression '*' expression
506 | expression '/' expression
511 | expression '%' expression
516 | expression '^' expression
521 | '-' expression %prec UNARY_MINUS
530 sprintf (genstr, "L%d:", -$1);
532 sprintf (genstr, "l%d:", $1);
537 int len = strlen($1);
539 if (len == 1 && *$1 == '0')
541 else if (len == 1 && *$1 == '1')
553 | NAME '(' opt_argument_list ')'
558 sprintf (genstr, "C%d,%s:",
565 sprintf (genstr, "C%d:", lookup ($1,FUNCT));
569 | INCR_DECR named_expression
575 sprintf (genstr, "DA%d:L%d:", -$2, -$2);
577 sprintf (genstr, "DM%d:L%d:", -$2, -$2);
582 sprintf (genstr, "i%d:l%d:", $2, $2);
584 sprintf (genstr, "d%d:l%d:", $2, $2);
588 | named_expression INCR_DECR
593 sprintf (genstr, "DL%d:x", -$1);
596 sprintf (genstr, "A%d:", -$1);
598 sprintf (genstr, "M%d:", -$1);
602 sprintf (genstr, "l%d:", $1);
605 sprintf (genstr, "i%d:", $1);
607 sprintf (genstr, "d%d:", $1);
611 | Length '(' expression ')'
612 { generate ("cL"); $$ = 1;}
613 | Sqrt '(' expression ')'
614 { generate ("cR"); $$ = 1;}
615 | Scale '(' expression ')'
616 { generate ("cS"); $$ = 1;}
619 warn ("read function");
620 generate ("cI"); $$ = 1;
623 named_expression : NAME
624 { $$ = lookup($1,SIMPLE); }
625 | NAME '[' expression ']'
627 if ($3 > 1) warn("comparison in subscript");
628 $$ = lookup($1,ARRAY);
638 warn ("History variable");
642 warn ("Last variable");
647 required_eol : { warn ("End of line required"); }
649 | required_eol ENDOFLINE
650 { warn ("Too many end of lines"); }