/* bc.y: The grammar for a POSIX compatable bc processor with some
extensions to the language. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* Extensions over POSIX bc.
a) NAME was LETTER. This grammer allows longer names.
Single letter names will still work.
b) Relational_expression allowed only one comparison.
This grammar has added boolean expressions with
&& (and) || (or) and ! (not) and allowed all of them in
c) Added an else to the if.
d) Call by variable array parameters
e) read() procedure that reads a number under program control from stdin.
f) halt statement that halts the the program under program control. It
is an executed statement.
g) continue statement for for loops.
h) optional expressions in the for loop.
i) print statement to print multiple numbers per line.
j) warranty statement to print an extended warranty notice.
j) limits statement to print the processor's limits.
%token <i_value> NEWLINE AND OR NOT
%token <s_value> STRING NAME NUMBER
/* '-', '+' are tokens themselves */
%token <c_value> ASSIGN_OP
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
/* '==', '<=', '>=', '!=', '<', '>' */
%token <c_value> INCR_DECR
%token <i_value> Define Break Quit Length
/* 'define', 'break', 'quit', 'length' */
%token <i_value> Return For If While Sqrt Else
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
%token <i_value> Scale Ibase Obase Auto Read
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
/* Types of all other things. */
%type <i_value> expression return_expression named_expression opt_expression
%type <a_value> opt_parameter_list opt_auto_define_list define_list
%type <a_value> opt_argument_list argument_list
%type <s_value> NAME STRING NUMBER
%type <i_value> program input_item semicolon_list statement_list
%type <i_value> statement function statement_or_error
%type <i_value> NEWLINE AND OR NOT
printf ("%s\n", BC_VERSION);
input_item : semicolon_list NEWLINE
semicolon_list : /* empty */
| semicolon_list ';' statement_or_error
statement_list : /* empty */
| statement_list NEWLINE statement_or_error
| statement_list ';' statement
statement_or_error : statement
warn ("comparison in expression");
yyerror ("Break outside a for/while");
sprintf (genstr, "J%1d:", break_label);
warn ("Continue statement");
yyerror ("Continue outside a for");
sprintf (genstr, "J%1d:", continue_label);
| Return '(' return_expression ')'
break_label = next_label++;
warn ("Comparison in first for expression");
sprintf (genstr, "N%1d:", $4);
sprintf (genstr, "pN%1d:", $4);
if ($7 < 0) generate ("1");
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
$<i_value>$ = continue_label;
continue_label = next_label++;
sprintf (genstr, "N%1d:", continue_label);
warn ("Comparison in third for expression");
sprintf (genstr, "J%1d:N%1d:", $4, $7);
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
sprintf (genstr, "J%1d:N%1d:",
continue_label, break_label);
continue_label = $<i_value>9;
sprintf (genstr, "Z%1d:", if_label);
sprintf (genstr, "N%1d:", if_label);
sprintf (genstr, "N%1d:", $1);
break_label = next_label++;
sprintf (genstr, "Z%1d:", break_label);
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
{ warn ("print statement"); }
print_list : print_element
| print_element ',' print_list
warn ("else clause in if statement");
sprintf (genstr, "J%d:N%1d:", $1, if_label);
function : Define NAME '(' opt_parameter_list ')' '{'
NEWLINE opt_auto_define_list
/* Check auto list against parameter list? */
sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
arg_str ($4,TRUE), arg_str ($8,TRUE));
statement_list NEWLINE '}'
opt_parameter_list : /* empty */
opt_auto_define_list : /* empty */
| Auto define_list NEWLINE
{ $$ = nextarg (NULL, lookup ($1,SIMPLE)); }
{ $$ = nextarg (NULL, lookup ($1,ARRAY)); }
{ $$ = nextarg ($1, lookup ($3,SIMPLE)); }
| define_list ',' NAME '[' ']'
{ $$ = nextarg ($1, lookup ($3,ARRAY)); }
opt_argument_list : /* empty */
argument_list : expression
if ($1 > 1) warn ("comparison in argument");
sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
| argument_list ',' expression
if ($3 > 1) warn ("comparison in argument");
| argument_list ',' NAME '[' ']'
sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
opt_expression : /* empty */
warn ("Missing expression in for statement");
return_expression : /* empty */
warn ("comparison in return expresion");
expression : named_expression ASSIGN_OP
sprintf (genstr, "DL%d:", -$1);
sprintf (genstr, "l%d:", $1);
if ($4 > 1) warn("comparison in assignment");
sprintf (genstr, "%c", $2);
sprintf (genstr, "S%d:", -$1);
sprintf (genstr, "s%d:", $1);
sprintf (genstr, "DZ%d:p", $2);
sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
sprintf (genstr, "B%d:", $2);
sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
| expression REL_OP expression
| expression '+' expression
| expression '-' expression
| expression MUL_OP expression
| expression '^' expression
| '-' expression %prec UNARY_MINUS
sprintf (genstr, "L%d:", -$1);
sprintf (genstr, "l%d:", $1);
if (len == 1 && *$1 == '0')
else if (len == 1 && *$1 == '1')
| NAME '(' opt_argument_list ')'
sprintf (genstr, "C%d,%s:",
sprintf (genstr, "C%d:", lookup ($1,FUNCT));
| INCR_DECR named_expression
sprintf (genstr, "DA%d:L%d:", -$2, -$2);
sprintf (genstr, "DM%d:L%d:", -$2, -$2);
sprintf (genstr, "i%d:l%d:", $2, $2);
sprintf (genstr, "d%d:l%d:", $2, $2);
| named_expression INCR_DECR
sprintf (genstr, "DL%d:x", -$1);
sprintf (genstr, "A%d:", -$1);
sprintf (genstr, "M%d:", -$1);
sprintf (genstr, "l%d:", $1);
sprintf (genstr, "i%d:", $1);
sprintf (genstr, "d%d:", $1);
| Length '(' expression ')'
{ generate ("cL"); $$ = 1;}
| Sqrt '(' expression ')'
{ generate ("cR"); $$ = 1;}
| Scale '(' expression ')'
{ generate ("cS"); $$ = 1;}
{ $$ = lookup($1,SIMPLE); }
| NAME '[' expression ']'
if ($3 > 1) warn("comparison in subscript");