Blame bc/bc.y

Packit 70b277
/*  This file is part of GNU bc.
Packit 70b277
Packit 70b277
    Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
Packit 70b277
Packit 70b277
    This program is free software; you can redistribute it and/or modify
Packit 70b277
    it under the terms of the GNU General Public License as published by
Packit 70b277
    the Free Software Foundation; either version 3 of the License , or
Packit 70b277
    (at your option) any later version.
Packit 70b277
Packit 70b277
    This program is distributed in the hope that it will be useful,
Packit 70b277
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 70b277
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 70b277
    GNU General Public License for more details.
Packit 70b277
Packit 70b277
    You should have received a copy of the GNU General Public License
Packit 70b277
    along with this program; see the file COPYING.  If not, see
Packit 70b277
    <http://www.gnu.org/licenses>.
Packit 70b277
Packit 70b277
    You may contact the author by:
Packit 70b277
       e-mail:  philnelson@acm.org
Packit 70b277
      us-mail:  Philip A. Nelson
Packit 70b277
                Computer Science Department, 9062
Packit 70b277
                Western Washington University
Packit 70b277
                Bellingham, WA 98226-9062
Packit 70b277
       
Packit 70b277
*************************************************************************/
Packit 70b277
Packit 70b277
/* bc.y: The grammar for a POSIX compatable bc processor with some
Packit 70b277
         extensions to the language. */
Packit 70b277
Packit 70b277
%{
Packit 70b277
Packit 70b277
#include "bcdefs.h"
Packit 70b277
#include "global.h"
Packit 70b277
#include "proto.h"
Packit 70b277
Packit 70b277
/* current function number. */
Packit 70b277
int cur_func = -1;
Packit 70b277
Packit 70b277
/* Expression encoded information -- See comment at expression rules. */
Packit 70b277
#define EX_ASSGN 0 
Packit 70b277
#define EX_REG   1
Packit 70b277
#define EX_COMP  2
Packit 70b277
#define EX_PAREN 4
Packit 70b277
#define EX_VOID  8 
Packit 70b277
#define EX_EMPTY 16
Packit 70b277
Packit 70b277
%}
Packit 70b277
Packit 70b277
%start program
Packit 70b277
Packit 70b277
%union {
Packit 70b277
	char	 *s_value;
Packit 70b277
	char	  c_value;
Packit 70b277
	int	  i_value;
Packit 70b277
	arg_list *a_value;
Packit 70b277
       }
Packit 70b277
Packit 70b277
/* Extensions over POSIX bc.
Packit 70b277
   a) NAME was LETTER.  This grammar allows longer names.
Packit 70b277
      Single letter names will still work.
Packit 70b277
   b) Relational_expression allowed only one comparison.
Packit 70b277
      This grammar has added boolean expressions with
Packit 70b277
      && (and) || (or) and ! (not) and allowed all of them in
Packit 70b277
      full expressions.
Packit 70b277
   c) Added an else to the if.
Packit 70b277
   d) Call by variable array parameters
Packit 70b277
   e) read() procedure that reads a number under program control from stdin.
Packit 70b277
   f) halt statement that halts the the program under program control.  It
Packit 70b277
      is an executed statement.
Packit 70b277
   g) continue statement for for loops.
Packit 70b277
   h) optional expressions in the for loop.
Packit 70b277
   i) print statement to print multiple numbers per line.
Packit 70b277
   j) warranty statement to print an extended warranty notice.
Packit 70b277
   k) limits statement to print the processor's limits.
Packit 70b277
   l) void functions.
Packit 70b277
*/
Packit 70b277
Packit 70b277
%token <i_value> ENDOFLINE AND OR NOT
Packit 70b277
%token <s_value> STRING NAME NUMBER
Packit 70b277
/*     '-', '+' are tokens themselves		*/
Packit 70b277
/*     '=', '+=',  '-=', '*=', '/=', '%=', '^=' */
Packit 70b277
%token <c_value> ASSIGN_OP
Packit 70b277
/*     '==', '<=', '>=', '!=', '<', '>' 	*/
Packit 70b277
%token <s_value> REL_OP
Packit 70b277
/*     '++', '--' 				*/
Packit 70b277
%token <c_value> INCR_DECR
Packit 70b277
/*     'define', 'break', 'quit', 'length' 	*/
Packit 70b277
%token <i_value> Define    Break    Quit    Length
Packit 70b277
/*     'return', 'for', 'if', 'while', 'sqrt', 'else' 	*/
Packit 70b277
%token <i_value> Return    For    If    While    Sqrt   Else
Packit 70b277
/*     'scale', 'ibase', 'obase', 'auto', 'read', 'random' 	*/
Packit 70b277
%token <i_value> Scale Ibase Obase Auto    Read    Random
Packit 70b277
/*     'warranty', 'halt', 'last', 'continue', 'print', 'limits'   */
Packit 70b277
%token <i_value> Warranty  Halt  Last  Continue  Print  Limits
Packit 70b277
/*     'history', 'void' */
Packit 70b277
%token <i_value> UNARY_MINUS HistoryVar Void
Packit 70b277
Packit 70b277
Packit 70b277
/* Types of all other things. */
Packit 70b277
%type <i_value> expression return_expression named_expression opt_expression
Packit 70b277
%type <c_value> '+' '-' '*' '/' '%' 
Packit 70b277
%type <a_value> opt_parameter_list opt_auto_define_list define_list
Packit 70b277
%type <a_value> opt_argument_list argument_list
Packit 70b277
%type <i_value> program input_item semicolon_list statement_list
Packit 70b277
%type <i_value> statement function statement_or_error required_eol
Packit 70b277
%type <i_value> opt_void
Packit 70b277
Packit 70b277
/* precedence */
Packit 70b277
%left OR
Packit 70b277
%left AND
Packit 70b277
%nonassoc NOT
Packit 70b277
%left REL_OP
Packit 70b277
%right ASSIGN_OP
Packit 70b277
%left '+' '-'
Packit 70b277
%left '*' '/' '%'
Packit 70b277
%right '^'
Packit 70b277
%nonassoc UNARY_MINUS
Packit 70b277
%nonassoc INCR_DECR
Packit 70b277
Packit 70b277
%%
Packit 70b277
program			: /* empty */
Packit 70b277
			    {
Packit 70b277
			      $$ = 0;
Packit 70b277
			      if (interactive && !quiet)
Packit 70b277
				{
Packit 70b277
				  show_bc_version ();
Packit 70b277
				  welcome ();
Packit 70b277
				}
Packit 70b277
			    }
Packit 70b277
			| program input_item
Packit 70b277
			;
Packit 70b277
input_item		: semicolon_list ENDOFLINE
Packit 70b277
			    { run_code (); }
Packit 70b277
			| function
Packit 70b277
			    { run_code (); }
Packit 70b277
			| error ENDOFLINE
Packit 70b277
			    {
Packit 70b277
			      yyerrok;
Packit 70b277
			      init_gen ();
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
opt_newline		: /* empty */
Packit 70b277
			| ENDOFLINE
Packit 70b277
			    { ct_warn ("newline not allowed"); }
Packit 70b277
			;
Packit 70b277
semicolon_list		: /* empty */
Packit 70b277
			    { $$ = 0; }
Packit 70b277
			| statement_or_error
Packit 70b277
			| semicolon_list ';' statement_or_error
Packit 70b277
			| semicolon_list ';'
Packit 70b277
			;
Packit 70b277
statement_list		: /* empty */
Packit 70b277
			    { $$ = 0; }
Packit 70b277
			| statement_or_error
Packit 70b277
			| statement_list ENDOFLINE
Packit 70b277
			| statement_list ENDOFLINE statement_or_error
Packit 70b277
			| statement_list ';'
Packit 70b277
			| statement_list ';' statement
Packit 70b277
			;
Packit 70b277
statement_or_error	: statement
Packit 70b277
  			| error statement
Packit 70b277
			    { $$ = $2; }
Packit 70b277
			;
Packit 70b277
statement 		: Warranty
Packit 70b277
			    { warranty (""); }
Packit 70b277
			| Limits
Packit 70b277
			    { limits (); }
Packit 70b277
			| expression
Packit 70b277
			    {
Packit 70b277
			      if ($1 & EX_COMP)
Packit 70b277
				ct_warn ("comparison in expression");
Packit 70b277
			      if ($1 & EX_REG)
Packit 70b277
				generate ("W");
Packit 70b277
			      else 
Packit 70b277
				generate ("p");
Packit 70b277
			    }
Packit 70b277
			| STRING
Packit 70b277
			    {
Packit 70b277
			      $$ = 0;
Packit 70b277
			      generate ("w");
Packit 70b277
			      generate ($1);
Packit 70b277
			      free ($1);
Packit 70b277
			    }
Packit 70b277
			| Break
Packit 70b277
			    {
Packit 70b277
			      if (break_label == 0)
Packit 70b277
				yyerror ("Break outside a for/while");
Packit 70b277
			      else
Packit 70b277
				{
Packit 70b277
				  snprintf (genstr, genlen, "J%1d:",
Packit 70b277
				  	    break_label);
Packit 70b277
				  generate (genstr);
Packit 70b277
				}
Packit 70b277
			    }
Packit 70b277
			| Continue
Packit 70b277
			    {
Packit 70b277
			      ct_warn ("Continue statement");
Packit 70b277
			      if (continue_label == 0)
Packit 70b277
				yyerror ("Continue outside a for");
Packit 70b277
			      else
Packit 70b277
				{
Packit 70b277
				  snprintf (genstr, genlen, "J%1d:", 
Packit 70b277
					    continue_label);
Packit 70b277
				  generate (genstr);
Packit 70b277
				}
Packit 70b277
			    }
Packit 70b277
			| Quit
Packit 70b277
			    { bc_exit (0); }
Packit 70b277
			| Halt
Packit 70b277
			    { generate ("h"); }
Packit 70b277
			| Return return_expression
Packit 70b277
			    { generate ("R"); }
Packit 70b277
			| For 
Packit 70b277
			    {
Packit 70b277
			      $1 = break_label; 
Packit 70b277
			      break_label = next_label++;
Packit 70b277
			    }
Packit 70b277
			  '(' opt_expression ';'
Packit 70b277
			    {
Packit 70b277
			      if ($4 & EX_COMP)
Packit 70b277
				ct_warn ("Comparison in first for expression");
Packit 70b277
			      if ($4 & EX_VOID)
Packit 70b277
				yyerror ("first expression is void");
Packit 70b277
			      if (!($4 & EX_EMPTY))
Packit 70b277
				generate ("p");
Packit 70b277
			      $4 = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "N%1d:", $4);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			  opt_expression ';'
Packit 70b277
			    {
Packit 70b277
			      if ($7 & EX_VOID)
Packit 70b277
				yyerror ("second expression is void");
Packit 70b277
			      if ($7 & EX_EMPTY ) generate ("1");
Packit 70b277
			      $7 = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "B%1d:J%1d:", $7,
Packit 70b277
			      		break_label);
Packit 70b277
			      generate (genstr);
Packit 70b277
			      $<i_value>$ = continue_label;
Packit 70b277
			      continue_label = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "N%1d:", 
Packit 70b277
			      		continue_label);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			  opt_expression ')'
Packit 70b277
			    {
Packit 70b277
			      if ($10 & EX_COMP)
Packit 70b277
				ct_warn ("Comparison in third for expression");
Packit 70b277
			      if ($10 & EX_VOID)
Packit 70b277
				yyerror ("third expression is void");
Packit 70b277
			      if ($10 & EX_EMPTY)
Packit 70b277
				snprintf (genstr, genlen, "J%1d:N%1d:", $4, $7);
Packit 70b277
			      else
Packit 70b277
				snprintf (genstr, genlen, "pJ%1d:N%1d:", $4, $7);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			  opt_newline statement
Packit 70b277
			    {
Packit 70b277
			      snprintf (genstr, genlen, "J%1d:N%1d:",
Packit 70b277
				       continue_label, break_label);
Packit 70b277
			      generate (genstr);
Packit 70b277
			      break_label = $1;
Packit 70b277
			      continue_label = $<i_value>9;
Packit 70b277
			    }
Packit 70b277
			| If '(' expression ')' 
Packit 70b277
			    {
Packit 70b277
			      if ($3 & EX_VOID)
Packit 70b277
				yyerror ("void expression");
Packit 70b277
			      $3 = if_label;
Packit 70b277
			      if_label = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "Z%1d:", if_label);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			  opt_newline statement  opt_else
Packit 70b277
			    {
Packit 70b277
			      snprintf (genstr, genlen, "N%1d:", if_label); 
Packit 70b277
			      generate (genstr);
Packit 70b277
			      if_label = $3;
Packit 70b277
			    }
Packit 70b277
			| While 
Packit 70b277
			    {
Packit 70b277
			      $1 = continue_label;
Packit 70b277
			      continue_label = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "N%1d:", 
Packit 70b277
					continue_label);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			'(' expression 
Packit 70b277
			    {
Packit 70b277
			      if ($4 & EX_VOID)
Packit 70b277
				yyerror ("void expression");
Packit 70b277
			      $4 = break_label; 
Packit 70b277
			      break_label = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "Z%1d:", break_label);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			')' opt_newline statement
Packit 70b277
			    {
Packit 70b277
			      snprintf (genstr, genlen, "J%1d:N%1d:", 
Packit 70b277
					continue_label, break_label);
Packit 70b277
			      generate (genstr);
Packit 70b277
			      break_label = $4;
Packit 70b277
			      continue_label = $1;
Packit 70b277
			    }
Packit 70b277
			| '{' statement_list '}'
Packit 70b277
			    { $$ = 0; }
Packit 70b277
			| Print
Packit 70b277
			    {  ct_warn ("print statement"); }
Packit 70b277
			  print_list
Packit 70b277
			;
Packit 70b277
print_list		: print_element
Packit 70b277
 			| print_element ',' print_list
Packit 70b277
			;
Packit 70b277
print_element		: STRING
Packit 70b277
			    {
Packit 70b277
			      generate ("O");
Packit 70b277
			      generate ($1);
Packit 70b277
			      free ($1);
Packit 70b277
			    }
Packit 70b277
			| expression
Packit 70b277
			    {
Packit 70b277
			      if ($1 & EX_VOID)
Packit 70b277
				yyerror ("void expression in print");
Packit 70b277
			      generate ("P");
Packit 70b277
			    }
Packit 70b277
 			;
Packit 70b277
opt_else		: /* nothing */
Packit 70b277
			| Else 
Packit 70b277
			    {
Packit 70b277
			      ct_warn ("else clause in if statement");
Packit 70b277
			      $1 = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "J%d:N%1d:", $1,
Packit 70b277
					if_label); 
Packit 70b277
			      generate (genstr);
Packit 70b277
			      if_label = $1;
Packit 70b277
			    }
Packit 70b277
			  opt_newline statement
Packit 70b277
			;
Packit 70b277
function 		: Define opt_void NAME '(' opt_parameter_list ')' opt_newline
Packit 70b277
     			  '{' required_eol opt_auto_define_list 
Packit 70b277
			    { char *params, *autos;
Packit 70b277
			      /* Check auto list against parameter list? */
Packit 70b277
			      check_params ($5,$10);
Packit 70b277
			      params = arg_str ($5);
Packit 70b277
			      autos  = arg_str ($10);
Packit 70b277
			      set_genstr_size (30 + strlen (params)
Packit 70b277
					       + strlen (autos));
Packit 70b277
			      cur_func = lookup($3,FUNCTDEF);
Packit 70b277
			      snprintf (genstr, genlen, "F%d,%s.%s[", cur_func,
Packit 70b277
					params, autos); 
Packit 70b277
			      generate (genstr);
Packit 70b277
			      functions[cur_func].f_void = $2;
Packit 70b277
			      free_args ($5);
Packit 70b277
			      free_args ($10);
Packit 70b277
			      $1 = next_label;
Packit 70b277
			      next_label = 1;
Packit 70b277
			    }
Packit 70b277
			  statement_list /* ENDOFLINE */ '}'
Packit 70b277
			    {
Packit 70b277
			      generate ("0R]");
Packit 70b277
			      next_label = $1;
Packit 70b277
			      cur_func = -1;
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
opt_void		: /* empty */
Packit 70b277
			    { $$ = 0; }
Packit 70b277
			| Void
Packit 70b277
			    {
Packit 70b277
			      $$ = 1;
Packit 70b277
			      ct_warn ("void functions");
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
opt_parameter_list	: /* empty */ 
Packit 70b277
			    { $$ = NULL; }
Packit 70b277
			| define_list
Packit 70b277
			;
Packit 70b277
opt_auto_define_list 	: /* empty */ 
Packit 70b277
			    { $$ = NULL; }
Packit 70b277
			| Auto define_list ENDOFLINE
Packit 70b277
			    { $$ = $2; } 
Packit 70b277
			| Auto define_list ';'
Packit 70b277
			    { $$ = $2; } 
Packit 70b277
			;
Packit 70b277
define_list 		: NAME
Packit 70b277
			    { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);}
Packit 70b277
			| NAME '[' ']'
Packit 70b277
			    { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
Packit 70b277
			| '*' NAME '[' ']'
Packit 70b277
			    { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE);
Packit 70b277
			      ct_warn ("Call by variable arrays");
Packit 70b277
			    }
Packit 70b277
			| '&' NAME '[' ']'
Packit 70b277
			    { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE);
Packit 70b277
			      ct_warn ("Call by variable arrays");
Packit 70b277
			    }
Packit 70b277
			| define_list ',' NAME
Packit 70b277
			    { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
Packit 70b277
			| define_list ',' NAME '[' ']'
Packit 70b277
			    { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
Packit 70b277
			| define_list ',' '*' NAME '[' ']'
Packit 70b277
			    { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE);
Packit 70b277
			      ct_warn ("Call by variable arrays");
Packit 70b277
			    }
Packit 70b277
			| define_list ',' '&' NAME '[' ']'
Packit 70b277
			    { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE);
Packit 70b277
			      ct_warn ("Call by variable arrays");
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
opt_argument_list	: /* empty */
Packit 70b277
			    { $$ = NULL; }
Packit 70b277
			| argument_list
Packit 70b277
			;
Packit 70b277
argument_list 		: expression
Packit 70b277
			    {
Packit 70b277
			      if ($1 & EX_COMP)
Packit 70b277
				ct_warn ("comparison in argument");
Packit 70b277
			      if ($1 & EX_VOID)
Packit 70b277
				yyerror ("void argument");
Packit 70b277
			      $$ = nextarg (NULL,0,FALSE);
Packit 70b277
			    }
Packit 70b277
			| NAME '[' ']'
Packit 70b277
			    {
Packit 70b277
			      snprintf (genstr, genlen, "K%d:",
Packit 70b277
					-lookup ($1,ARRAY));
Packit 70b277
			      generate (genstr);
Packit 70b277
			      $$ = nextarg (NULL,1,FALSE);
Packit 70b277
			    }
Packit 70b277
			| argument_list ',' expression
Packit 70b277
			    {
Packit 70b277
			      if ($3 & EX_COMP)
Packit 70b277
				ct_warn ("comparison in argument");
Packit 70b277
			      if ($3 & EX_VOID)
Packit 70b277
				yyerror ("void argument");
Packit 70b277
			      $$ = nextarg ($1,0,FALSE);
Packit 70b277
			    }
Packit 70b277
			| argument_list ',' NAME '[' ']'
Packit 70b277
			    {
Packit 70b277
			      snprintf (genstr, genlen, "K%d:", 
Packit 70b277
					-lookup ($3,ARRAY));
Packit 70b277
			      generate (genstr);
Packit 70b277
			      $$ = nextarg ($1,1,FALSE);
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
Packit 70b277
/* Expression lval meanings!  (Bits mean something!)  (See defines above)
Packit 70b277
 *  0 => Top op is assignment.
Packit 70b277
 *  1 => Top op is not assignment.
Packit 70b277
 *  2 => Comparison is somewhere in expression.
Packit 70b277
 *  4 => Expression is in parenthesis.
Packit 70b277
 *  8 => Expression is void!
Packit 70b277
 * 16 => Empty optional expression.
Packit 70b277
 */
Packit 70b277
Packit 70b277
opt_expression 		: /* empty */
Packit 70b277
			    {
Packit 70b277
			      $$ = EX_EMPTY;
Packit 70b277
			      ct_warn ("Missing expression in for statement");
Packit 70b277
			    }
Packit 70b277
			| expression
Packit 70b277
			;
Packit 70b277
return_expression	: /* empty */
Packit 70b277
			    {
Packit 70b277
			      $$ = 0;
Packit 70b277
			      generate ("0");
Packit 70b277
			      if (cur_func == -1)
Packit 70b277
				yyerror("Return outside of a function.");
Packit 70b277
			    }
Packit 70b277
			| expression
Packit 70b277
			    {
Packit 70b277
			      if ($1 & EX_COMP)
Packit 70b277
				ct_warn ("comparison in return expresion");
Packit 70b277
			      if (!($1 & EX_PAREN))
Packit 70b277
				ct_warn ("return expression requires parenthesis");
Packit 70b277
			      if ($1 & EX_VOID)
Packit 70b277
				yyerror("return requires non-void expression");
Packit 70b277
			      if (cur_func == -1)
Packit 70b277
				yyerror("Return outside of a function.");
Packit 70b277
			      else if (functions[cur_func].f_void)
Packit 70b277
				yyerror("Return expression in a void function.");
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
expression		:  named_expression ASSIGN_OP 
Packit 70b277
			    {
Packit 70b277
			      if ($2 != '=')
Packit 70b277
				{
Packit 70b277
				  if ($1 < 0)
Packit 70b277
				    snprintf (genstr, genlen, "DL%d:", -$1);
Packit 70b277
				  else
Packit 70b277
				    snprintf (genstr, genlen, "l%d:", $1);
Packit 70b277
				  generate (genstr);
Packit 70b277
				}
Packit 70b277
			    }
Packit 70b277
			  expression
Packit 70b277
			    {
Packit 70b277
			      if ($4 & EX_ASSGN)
Packit 70b277
				ct_warn("comparison in assignment");
Packit 70b277
			      if ($4 & EX_VOID)
Packit 70b277
				yyerror("Assignment of a void expression");
Packit 70b277
			      if ($2 != '=')
Packit 70b277
				{
Packit 70b277
				  snprintf (genstr, genlen, "%c", $2);
Packit 70b277
				  generate (genstr);
Packit 70b277
				}
Packit 70b277
			      if ($1 < 0)
Packit 70b277
				snprintf (genstr, genlen, "S%d:", -$1);
Packit 70b277
			      else
Packit 70b277
				snprintf (genstr, genlen, "s%d:", $1);
Packit 70b277
			      generate (genstr);
Packit 70b277
			      $$ = EX_ASSGN;
Packit 70b277
			    }
Packit 70b277
			| expression AND 
Packit 70b277
			    {
Packit 70b277
			      ct_warn("&& operator");
Packit 70b277
			      $2 = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "DZ%d:p", $2);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			  expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($4 & EX_VOID))
Packit 70b277
				yyerror ("void expression with &&";;
Packit 70b277
			      snprintf (genstr, genlen, "DZ%d:p1N%d:", $2, $2);
Packit 70b277
			      generate (genstr);
Packit 70b277
			      $$ = ($1 | $4) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| expression OR
Packit 70b277
			    {
Packit 70b277
			      ct_warn("|| operator");
Packit 70b277
			      $2 = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "B%d:", $2);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			  expression
Packit 70b277
 			    {
Packit 70b277
			      int tmplab;
Packit 70b277
			      if (($1 & EX_VOID) || ($4 & EX_VOID))
Packit 70b277
				yyerror ("void expression with ||");
Packit 70b277
			      tmplab = next_label++;
Packit 70b277
			      snprintf (genstr, genlen, "B%d:0J%d:N%d:1N%d:",
Packit 70b277
				       $2, tmplab, $2, tmplab);
Packit 70b277
			      generate (genstr);
Packit 70b277
			      $$ = ($1 | $4) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| NOT expression
Packit 70b277
			    {
Packit 70b277
			      if ($2 & EX_VOID)
Packit 70b277
				yyerror ("void expression with !");
Packit 70b277
			      $$ = $2 & ~EX_PAREN;
Packit 70b277
			      ct_warn("! operator");
Packit 70b277
			      generate ("!");
Packit 70b277
			    }
Packit 70b277
			| expression REL_OP expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($3 & EX_VOID))
Packit 70b277
				yyerror ("void expression with comparison");
Packit 70b277
			      $$ = EX_REG | EX_COMP;
Packit 70b277
			      switch (*($2))
Packit 70b277
				{
Packit 70b277
				case '=':
Packit 70b277
				  generate ("=");
Packit 70b277
				  break;
Packit 70b277
Packit 70b277
				case '!':
Packit 70b277
				  generate ("#");
Packit 70b277
				  break;
Packit 70b277
Packit 70b277
				case '<':
Packit 70b277
				  if ($2[1] == '=')
Packit 70b277
				    generate ("{");
Packit 70b277
				  else
Packit 70b277
				    generate ("<");
Packit 70b277
				  break;
Packit 70b277
Packit 70b277
				case '>':
Packit 70b277
				  if ($2[1] == '=')
Packit 70b277
				    generate ("}");
Packit 70b277
				  else
Packit 70b277
				    generate (">");
Packit 70b277
				  break;
Packit 70b277
				}
Packit 70b277
                              free($2);
Packit 70b277
			    }
Packit 70b277
			| expression '+' expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($3 & EX_VOID))
Packit 70b277
				yyerror ("void expression with +");
Packit 70b277
			      generate ("+");
Packit 70b277
			      $$ = ($1 | $3) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| expression '-' expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($3 & EX_VOID))
Packit 70b277
				yyerror ("void expression with -");
Packit 70b277
			      generate ("-");
Packit 70b277
			      $$ = ($1 | $3) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| expression '*' expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($3 & EX_VOID))
Packit 70b277
				yyerror ("void expression with *");
Packit 70b277
			      generate ("*");
Packit 70b277
			      $$ = ($1 | $3) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| expression '/' expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($3 & EX_VOID))
Packit 70b277
				yyerror ("void expression with /");
Packit 70b277
			      generate ("/");
Packit 70b277
			      $$ = ($1 | $3) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| expression '%' expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($3 & EX_VOID))
Packit 70b277
				yyerror ("void expression with %");
Packit 70b277
			      generate ("%");
Packit 70b277
			      $$ = ($1 | $3) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| expression '^' expression
Packit 70b277
			    {
Packit 70b277
			      if (($1 & EX_VOID) || ($3 & EX_VOID))
Packit 70b277
				yyerror ("void expression with ^");
Packit 70b277
			      generate ("^");
Packit 70b277
			      $$ = ($1 | $3) & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| '-' expression  %prec UNARY_MINUS
Packit 70b277
			    {
Packit 70b277
			      if ($2 & EX_VOID)
Packit 70b277
				yyerror ("void expression with unary -");
Packit 70b277
			      generate ("n");
Packit 70b277
			      $$ = $2 & ~EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| named_expression
Packit 70b277
			    {
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			      if ($1 < 0)
Packit 70b277
				snprintf (genstr, genlen, "L%d:", -$1);
Packit 70b277
			      else
Packit 70b277
				snprintf (genstr, genlen, "l%d:", $1);
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			| NUMBER
Packit 70b277
			    {
Packit 70b277
			      int len = strlen($1);
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			      if (len == 1 && *$1 == '0')
Packit 70b277
				generate ("0");
Packit 70b277
			      else if (len == 1 && *$1 == '1')
Packit 70b277
				generate ("1");
Packit 70b277
			      else
Packit 70b277
				{
Packit 70b277
				  generate ("K");
Packit 70b277
				  generate ($1);
Packit 70b277
				  generate (":");
Packit 70b277
				}
Packit 70b277
			      free ($1);
Packit 70b277
			    }
Packit 70b277
			| '(' expression ')'
Packit 70b277
			    { 
Packit 70b277
			      if ($2 & EX_VOID)
Packit 70b277
				yyerror ("void expression in parenthesis");
Packit 70b277
			      $$ = $2 | EX_REG | EX_PAREN;
Packit 70b277
			    }
Packit 70b277
			| NAME '(' opt_argument_list ')'
Packit 70b277
			    { int fn;
Packit 70b277
			      fn = lookup ($1,FUNCT);
Packit 70b277
			      if (functions[fn].f_void)
Packit 70b277
				$$ = EX_VOID;
Packit 70b277
			      else
Packit 70b277
				$$ = EX_REG;
Packit 70b277
			      if ($3 != NULL)
Packit 70b277
				{ char *params = call_str ($3);
Packit 70b277
				  set_genstr_size (20 + strlen (params));
Packit 70b277
				  snprintf (genstr, genlen, "C%d,%s:", fn,
Packit 70b277
				  	    params);
Packit 70b277
				  free_args ($3);
Packit 70b277
				}
Packit 70b277
			      else
Packit 70b277
				{
Packit 70b277
				  snprintf (genstr, genlen, "C%d:", fn);
Packit 70b277
				}
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			| INCR_DECR named_expression
Packit 70b277
			    {
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			      if ($2 < 0)
Packit 70b277
				{
Packit 70b277
				  if ($1 == '+')
Packit 70b277
				    snprintf (genstr, genlen, "DA%d:L%d:", -$2, -$2);
Packit 70b277
				  else
Packit 70b277
				    snprintf (genstr, genlen, "DM%d:L%d:", -$2, -$2);
Packit 70b277
				}
Packit 70b277
			      else
Packit 70b277
				{
Packit 70b277
				  if ($1 == '+')
Packit 70b277
				    snprintf (genstr, genlen, "i%d:l%d:", $2, $2);
Packit 70b277
				  else
Packit 70b277
				    snprintf (genstr, genlen, "d%d:l%d:", $2, $2);
Packit 70b277
				}
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			| named_expression INCR_DECR
Packit 70b277
			    {
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			      if ($1 < 0)
Packit 70b277
				{
Packit 70b277
				  snprintf (genstr, genlen, "DL%d:x", -$1);
Packit 70b277
				  generate (genstr); 
Packit 70b277
				  if ($2 == '+')
Packit 70b277
				    snprintf (genstr, genlen, "A%d:", -$1);
Packit 70b277
				  else
Packit 70b277
				      snprintf (genstr, genlen, "M%d:", -$1);
Packit 70b277
				}
Packit 70b277
			      else
Packit 70b277
				{
Packit 70b277
				  snprintf (genstr, genlen, "l%d:", $1);
Packit 70b277
				  generate (genstr);
Packit 70b277
				  if ($2 == '+')
Packit 70b277
				    snprintf (genstr, genlen, "i%d:", $1);
Packit 70b277
				  else
Packit 70b277
				    snprintf (genstr, genlen, "d%d:", $1);
Packit 70b277
				}
Packit 70b277
			      generate (genstr);
Packit 70b277
			    }
Packit 70b277
			| Length '(' expression ')'
Packit 70b277
			    {
Packit 70b277
			      if ($3 & EX_VOID)
Packit 70b277
				yyerror ("void expression in length()");
Packit 70b277
			      generate ("cL");
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			    }
Packit 70b277
			| Sqrt '(' expression ')'
Packit 70b277
			    {
Packit 70b277
			      if ($3 & EX_VOID)
Packit 70b277
				yyerror ("void expression in sqrt()");
Packit 70b277
			      generate ("cR");
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			    }
Packit 70b277
			| Scale '(' expression ')'
Packit 70b277
			    {
Packit 70b277
			      if ($3 & EX_VOID)
Packit 70b277
				yyerror ("void expression in scale()");
Packit 70b277
			      generate ("cS");
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			    }
Packit 70b277
			| Read '(' ')'
Packit 70b277
			    {
Packit 70b277
			      ct_warn ("read function");
Packit 70b277
			      generate ("cI");
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			    }
Packit 70b277
			| Random '(' ')'
Packit 70b277
			    {
Packit 70b277
			      ct_warn ("random function");
Packit 70b277
			      generate ("cX");
Packit 70b277
			      $$ = EX_REG;
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
named_expression	: NAME
Packit 70b277
			    { $$ = lookup($1,SIMPLE); }
Packit 70b277
			| NAME '[' expression ']'
Packit 70b277
			    {
Packit 70b277
			      if ($3 & EX_VOID)
Packit 70b277
				yyerror("void expression as subscript");
Packit 70b277
			      if ($3 & EX_COMP)
Packit 70b277
				ct_warn("comparison in subscript");
Packit 70b277
			      $$ = lookup($1,ARRAY);
Packit 70b277
			    }
Packit 70b277
			| Ibase
Packit 70b277
			    { $$ = 0; }
Packit 70b277
			| Obase
Packit 70b277
			    { $$ = 1; }
Packit 70b277
			| Scale
Packit 70b277
			    { $$ = 2; }
Packit 70b277
			| HistoryVar
Packit 70b277
			    { $$ = 3;
Packit 70b277
			      ct_warn ("History variable");
Packit 70b277
			    }
Packit 70b277
			| Last
Packit 70b277
			    { $$ = 4;
Packit 70b277
			      ct_warn ("Last variable");
Packit 70b277
			    }
Packit 70b277
			;
Packit 70b277
Packit 70b277
Packit 70b277
required_eol		: { ct_warn ("End of line required"); }
Packit 70b277
			| ENDOFLINE
Packit 70b277
			| required_eol ENDOFLINE
Packit 70b277
			  { ct_warn ("Too many end of lines"); }
Packit 70b277
			;
Packit 70b277
Packit 70b277
%%