"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