summaryrefslogtreecommitdiff
path: root/bc/bc.y
diff options
context:
space:
mode:
Diffstat (limited to 'bc/bc.y')
-rw-r--r--bc/bc.y262
1 files changed, 195 insertions, 67 deletions
diff --git a/bc/bc.y b/bc/bc.y
index 403e326..14dc4be 100644
--- a/bc/bc.y
+++ b/bc/bc.y
@@ -1,9 +1,6 @@
-%{
-/* bc.y: The grammar for a POSIX compatable bc processor with some
- extensions to the language. */
-
/* This file is part of GNU bc.
- Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
+
+ Copyright (C) 1991-1994, 1997, 2006 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
@@ -18,8 +15,8 @@
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, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111 USA
+ Foundation, Inc. 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA
You may contact the author by:
e-mail: philnelson@acm.org
@@ -30,9 +27,26 @@
*************************************************************************/
+/* bc.y: The grammar for a POSIX compatable bc processor with some
+ extensions to the language. */
+
+%{
+
#include "bcdefs.h"
#include "global.h"
#include "proto.h"
+
+/* current function number. */
+int cur_func = -1;
+
+/* Expression encoded information -- See comment at expression rules. */
+#define EX_ASSGN 0
+#define EX_REG 1
+#define EX_COMP 2
+#define EX_PAREN 4
+#define EX_VOID 8
+#define EX_EMPTY 16
+
%}
%start program
@@ -76,12 +90,13 @@
%token <i_value> Define Break Quit Length
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
%token <i_value> Return For If While Sqrt Else
-/* 'scale', 'ibase', 'obase', 'auto', 'read' */
-%token <i_value> Scale Ibase Obase Auto Read
+/* 'scale', 'ibase', 'obase', 'auto', 'read', 'random' */
+%token <i_value> Scale Ibase Obase Auto Read Random
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
-%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
-/* 'history' */
-%token <i_value> UNARY_MINUS HistoryVar
+%token <i_value> Warranty Halt Last Continue Print Limits
+/* 'history', 'void' */
+%token <i_value> UNARY_MINUS HistoryVar Void
+
/* Types of all other things. */
%type <i_value> expression return_expression named_expression opt_expression
@@ -90,6 +105,7 @@
%type <a_value> opt_argument_list argument_list
%type <i_value> program input_item semicolon_list statement_list
%type <i_value> statement function statement_or_error required_eol
+%type <i_value> opt_void
/* precedence */
%left OR
@@ -153,9 +169,9 @@ statement : Warranty
{ limits (); }
| expression
{
- if ($1 & 2)
+ if ($1 & EX_COMP)
warn ("comparison in expression");
- if ($1 & 1)
+ if ($1 & EX_REG)
generate ("W");
else
generate ("p");
@@ -201,9 +217,11 @@ statement : Warranty
}
'(' opt_expression ';'
{
- if ($4 & 2)
+ if ($4 & EX_COMP)
warn ("Comparison in first for expression");
- if ($4 >= 0)
+ if ($4 & EX_VOID)
+ yyerror ("first expression is void");
+ if (!($4 & EX_EMPTY))
generate ("p");
$4 = next_label++;
sprintf (genstr, "N%1d:", $4);
@@ -211,7 +229,9 @@ statement : Warranty
}
opt_expression ';'
{
- if ($7 < 0) generate ("1");
+ if ($7 & EX_VOID)
+ yyerror ("second expression is void");
+ if ($7 & EX_EMPTY ) generate ("1");
$7 = next_label++;
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
generate (genstr);
@@ -222,9 +242,11 @@ statement : Warranty
}
opt_expression ')'
{
- if ($10 & 2 )
+ if ($10 & EX_COMP)
warn ("Comparison in third for expression");
- if ($10 & 16)
+ if ($10 & EX_VOID)
+ yyerror ("third expression is void");
+ if ($10 & EX_EMPTY)
sprintf (genstr, "J%1d:N%1d:", $4, $7);
else
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
@@ -240,6 +262,8 @@ statement : Warranty
}
| If '(' expression ')'
{
+ if ($3 & EX_VOID)
+ yyerror ("void expression");
$3 = if_label;
if_label = next_label++;
sprintf (genstr, "Z%1d:", if_label);
@@ -259,6 +283,8 @@ statement : Warranty
}
'(' expression
{
+ if ($4 & EX_VOID)
+ yyerror ("void expression");
$4 = break_label;
break_label = next_label++;
sprintf (genstr, "Z%1d:", break_label);
@@ -286,7 +312,11 @@ print_element : STRING
free ($1);
}
| expression
- { generate ("P"); }
+ {
+ if ($1 & EX_VOID)
+ yyerror ("void expression in print");
+ generate ("P");
+ }
;
opt_else : /* nothing */
| Else
@@ -298,17 +328,23 @@ opt_else : /* nothing */
if_label = $1;
}
opt_newline statement
-function : Define NAME '(' opt_parameter_list ')' opt_newline
+ ;
+function : Define opt_void NAME '(' opt_parameter_list ')' opt_newline
'{' required_eol opt_auto_define_list
- {
+ { char *params, *autos;
/* Check auto list against parameter list? */
- check_params ($4,$9);
- sprintf (genstr, "F%d,%s.%s[",
- lookup($2,FUNCTDEF),
- arg_str ($4), arg_str ($9));
+ check_params ($5,$10);
+ params = arg_str ($5);
+ autos = arg_str ($10);
+ set_genstr_size (30 + strlen (params)
+ + strlen (autos));
+ cur_func = lookup($3,FUNCTDEF);
+ sprintf (genstr, "F%d,%s.%s[", cur_func, params,
+ autos);
generate (genstr);
- free_args ($4);
- free_args ($9);
+ functions[cur_func].f_void = $2;
+ free_args ($5);
+ free_args ($10);
$1 = next_label;
next_label = 1;
}
@@ -316,6 +352,15 @@ function : Define NAME '(' opt_parameter_list ')' opt_newline
{
generate ("0R]");
next_label = $1;
+ cur_func = -1;
+ }
+ ;
+opt_void : /* empty */
+ { $$ = 0; }
+ | Void
+ {
+ $$ = 1;
+ warn ("void functions");
}
;
opt_parameter_list : /* empty */
@@ -334,13 +379,25 @@ define_list : NAME
| NAME '[' ']'
{ $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
| '*' NAME '[' ']'
- { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); }
+ { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
+ | '&' NAME '[' ']'
+ { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
| define_list ',' NAME
{ $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
| define_list ',' NAME '[' ']'
{ $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
| define_list ',' '*' NAME '[' ']'
- { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); }
+ { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
+ | define_list ',' '&' NAME '[' ']'
+ { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE);
+ warn ("Call by variable arrays");
+ }
;
opt_argument_list : /* empty */
{ $$ = NULL; }
@@ -348,7 +405,10 @@ opt_argument_list : /* empty */
;
argument_list : expression
{
- if ($1 & 2) warn ("comparison in argument");
+ if ($1 & EX_COMP)
+ warn ("comparison in argument");
+ if ($1 & EX_VOID)
+ yyerror ("void argument");
$$ = nextarg (NULL,0,FALSE);
}
| NAME '[' ']'
@@ -359,7 +419,10 @@ argument_list : expression
}
| argument_list ',' expression
{
- if ($3 & 2) warn ("comparison in argument");
+ if ($3 & EX_COMP)
+ warn ("comparison in argument");
+ if ($3 & EX_VOID)
+ yyerror ("void argument");
$$ = nextarg ($1,0,FALSE);
}
| argument_list ',' NAME '[' ']'
@@ -370,17 +433,18 @@ argument_list : expression
}
;
-/* Expression lval meanings! (Bits mean something!)
+/* Expression lval meanings! (Bits mean something!) (See defines above)
* 0 => Top op is assignment.
* 1 => Top op is not assignment.
* 2 => Comparison is somewhere in expression.
* 4 => Expression is in parenthesis.
+ * 8 => Expression is void!
* 16 => Empty optional expression.
*/
opt_expression : /* empty */
{
- $$ = 16;
+ $$ = EX_EMPTY;
warn ("Missing expression in for statement");
}
| expression
@@ -389,13 +453,21 @@ return_expression : /* empty */
{
$$ = 0;
generate ("0");
+ if (cur_func == -1)
+ yyerror("Return outside of a function.");
}
| expression
{
- if ($1 & 2)
+ if ($1 & EX_COMP)
warn ("comparison in return expresion");
- if (!($1 & 4))
+ if (!($1 & EX_PAREN))
warn ("return expression requires parenthesis");
+ if ($1 & EX_VOID)
+ yyerror("return requires non-void expression");
+ if (cur_func == -1)
+ yyerror("Return outside of a function.");
+ else if (functions[cur_func].f_void)
+ yyerror("Return expression in a void function.");
}
;
expression : named_expression ASSIGN_OP
@@ -411,7 +483,10 @@ expression : named_expression ASSIGN_OP
}
expression
{
- if ($4 & 2) warn("comparison in assignment");
+ if ($4 & EX_ASSGN)
+ warn("comparison in assignment");
+ if ($4 & EX_VOID)
+ yyerror("Assignment of a void expression");
if ($2 != '=')
{
sprintf (genstr, "%c", $2);
@@ -422,9 +497,8 @@ expression : named_expression ASSIGN_OP
else
sprintf (genstr, "s%d:", $1);
generate (genstr);
- $$ = 0;
+ $$ = EX_ASSGN;
}
- ;
| expression AND
{
warn("&& operator");
@@ -434,9 +508,11 @@ expression : named_expression ASSIGN_OP
}
expression
{
+ if (($1 & EX_VOID) || ($4 & EX_VOID))
+ yyerror ("void expression with &&");
sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
generate (genstr);
- $$ = ($1 | $4) & ~4;
+ $$ = ($1 | $4) & ~EX_PAREN;
}
| expression OR
{
@@ -448,21 +524,27 @@ expression : named_expression ASSIGN_OP
expression
{
int tmplab;
+ if (($1 & EX_VOID) || ($4 & EX_VOID))
+ yyerror ("void expression with ||");
tmplab = next_label++;
sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
$2, tmplab, $2, tmplab);
generate (genstr);
- $$ = ($1 | $4) & ~4;
+ $$ = ($1 | $4) & ~EX_PAREN;
}
| NOT expression
{
- $$ = $2 & ~4;
+ if ($2 & EX_VOID)
+ yyerror ("void expression with !");
+ $$ = $2 & ~EX_PAREN;
warn("! operator");
generate ("!");
}
| expression REL_OP expression
{
- $$ = 3;
+ if (($1 & EX_VOID) || ($3 & EX_VOID))
+ yyerror ("void expression with comparison");
+ $$ = EX_REG | EX_COMP;
switch (*($2))
{
case '=':
@@ -490,42 +572,56 @@ expression : named_expression ASSIGN_OP
}
| expression '+' expression
{
+ if (($1 & EX_VOID) || ($3 & EX_VOID))
+ yyerror ("void expression with +");
generate ("+");
- $$ = ($1 | $3) & ~4;
+ $$ = ($1 | $3) & ~EX_PAREN;
}
| expression '-' expression
{
+ if (($1 & EX_VOID) || ($3 & EX_VOID))
+ yyerror ("void expression with -");
generate ("-");
- $$ = ($1 | $3) & ~4;
+ $$ = ($1 | $3) & ~EX_PAREN;
}
| expression '*' expression
{
+ if (($1 & EX_VOID) || ($3 & EX_VOID))
+ yyerror ("void expression with *");
generate ("*");
- $$ = ($1 | $3) & ~4;
+ $$ = ($1 | $3) & ~EX_PAREN;
}
| expression '/' expression
{
+ if (($1 & EX_VOID) || ($3 & EX_VOID))
+ yyerror ("void expression with /");
generate ("/");
- $$ = ($1 | $3) & ~4;
+ $$ = ($1 | $3) & ~EX_PAREN;
}
| expression '%' expression
{
+ if (($1 & EX_VOID) || ($3 & EX_VOID))
+ yyerror ("void expression with %");
generate ("%");
- $$ = ($1 | $3) & ~4;
+ $$ = ($1 | $3) & ~EX_PAREN;
}
| expression '^' expression
{
+ if (($1 & EX_VOID) || ($3 & EX_VOID))
+ yyerror ("void expression with ^");
generate ("^");
- $$ = ($1 | $3) & ~4;
+ $$ = ($1 | $3) & ~EX_PAREN;
}
| '-' expression %prec UNARY_MINUS
{
+ if ($2 & EX_VOID)
+ yyerror ("void expression with unary -");
generate ("n");
- $$ = $2 & ~4;
+ $$ = $2 & ~EX_PAREN;
}
| named_expression
{
- $$ = 1;
+ $$ = EX_REG;
if ($1 < 0)
sprintf (genstr, "L%d:", -$1);
else
@@ -535,7 +631,7 @@ expression : named_expression ASSIGN_OP
| NUMBER
{
int len = strlen($1);
- $$ = 1;
+ $$ = EX_REG;
if (len == 1 && *$1 == '0')
generate ("0");
else if (len == 1 && *$1 == '1')
@@ -549,26 +645,33 @@ expression : named_expression ASSIGN_OP
free ($1);
}
| '(' expression ')'
- { $$ = $2 | 5; }
+ {
+ if ($2 & EX_VOID)
+ yyerror ("void expression in parenthesis");
+ $$ = $2 | EX_REG | EX_PAREN;
+ }
| NAME '(' opt_argument_list ')'
- {
- $$ = 1;
+ { int fn;
+ fn = lookup ($1,FUNCT);
+ if (functions[fn].f_void)
+ $$ = EX_VOID;
+ else
+ $$ = EX_REG;
if ($3 != NULL)
- {
- sprintf (genstr, "C%d,%s:",
- lookup ($1,FUNCT),
- call_str ($3));
+ { char *params = call_str ($3);
+ set_genstr_size (20 + strlen (params));
+ sprintf (genstr, "C%d,%s:", fn, params);
free_args ($3);
}
else
{
- sprintf (genstr, "C%d:", lookup ($1,FUNCT));
+ sprintf (genstr, "C%d:", fn);
}
generate (genstr);
}
| INCR_DECR named_expression
{
- $$ = 1;
+ $$ = EX_REG;
if ($2 < 0)
{
if ($1 == '+')
@@ -587,7 +690,7 @@ expression : named_expression ASSIGN_OP
}
| named_expression INCR_DECR
{
- $$ = 1;
+ $$ = EX_REG;
if ($1 < 0)
{
sprintf (genstr, "DL%d:x", -$1);
@@ -609,22 +712,47 @@ expression : named_expression ASSIGN_OP
generate (genstr);
}
| Length '(' expression ')'
- { generate ("cL"); $$ = 1;}
+ {
+ if ($3 & EX_VOID)
+ yyerror ("void expression in length()");
+ generate ("cL");
+ $$ = EX_REG;
+ }
| Sqrt '(' expression ')'
- { generate ("cR"); $$ = 1;}
+ {
+ if ($3 & EX_VOID)
+ yyerror ("void expression in sqrt()");
+ generate ("cR");
+ $$ = EX_REG;
+ }
| Scale '(' expression ')'
- { generate ("cS"); $$ = 1;}
+ {
+ if ($3 & EX_VOID)
+ yyerror ("void expression in scale()");
+ generate ("cS");
+ $$ = EX_REG;
+ }
| Read '(' ')'
{
warn ("read function");
- generate ("cI"); $$ = 1;
+ generate ("cI");
+ $$ = EX_REG;
+ }
+ | Random '(' ')'
+ {
+ warn ("random function");
+ generate ("cX");
+ $$ = EX_REG;
}
;
named_expression : NAME
{ $$ = lookup($1,SIMPLE); }
| NAME '[' expression ']'
{
- if ($3 > 1) warn("comparison in subscript");
+ if ($3 & EX_VOID)
+ yyerror("void expression as subscript");
+ if ($3 & EX_COMP)
+ warn("comparison in subscript");
$$ = lookup($1,ARRAY);
}
| Ibase