summaryrefslogtreecommitdiff
path: root/bc/sbc.y
diff options
context:
space:
mode:
Diffstat (limited to 'bc/sbc.y')
-rw-r--r--bc/sbc.y448
1 files changed, 448 insertions, 0 deletions
diff --git a/bc/sbc.y b/bc/sbc.y
new file mode 100644
index 0000000..b1ff1d1
--- /dev/null
+++ b/bc/sbc.y
@@ -0,0 +1,448 @@
+%{
+/* sbc.y: A POSIX bc processor written for minix with no extensions. */
+
+/* This file is part of GNU bc.
+ Copyright (C) 1991, 1992, 1993, 1994, 1997 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, Inc.
+ 59 Temple Place, Suite 330
+ Boston, MA 02111 USA
+
+ You may contact the author by:
+ e-mail: philnelson@acm.org
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include "bcdefs.h"
+#include "global.h" /* To get the global variables. */
+#include "proto.h"
+%}
+
+%start program
+
+%union {
+ char *s_value;
+ char c_value;
+ int i_value;
+ arg_list *a_value;
+ }
+
+%token <i_value> ENDOFLINE AND OR NOT
+%token <s_value> STRING NAME NUMBER
+/* '-', '+' are tokens themselves */
+%token <c_value> ASSIGN_OP
+/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
+%token <s_value> REL_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' */
+
+/* The types of all other non-terminals. */
+%type <i_value> expression named_expression return_expression
+%type <a_value> opt_parameter_list parameter_list opt_auto_define_list
+%type <a_value> define_list opt_argument_list argument_list
+%type <i_value> program input_item semicolon_list statement_list
+%type <i_value> statement_or_error statement function relational_expression
+
+/* precedence */
+%nonassoc REL_OP
+%right ASSIGN_OP
+%left '+' '-'
+%left '*' '/' '%'
+%right '^'
+%nonassoc UNARY_MINUS
+%nonassoc INCR_DECR
+
+%%
+program : /* empty */
+ {
+ $$ = 0;
+ std_only = TRUE;
+ if (interactive)
+ {
+ printf ("s%s\n", BC_VERSION);
+ welcome();
+ }
+ }
+ | program input_item
+ ;
+input_item : semicolon_list ENDOFLINE
+ { run_code(); }
+ | function
+ { run_code(); }
+ | error ENDOFLINE
+ {
+ yyerrok;
+ init_gen() ;
+ }
+ ;
+semicolon_list : /* empty */
+ { $$ = 0; }
+ | statement_or_error
+ | semicolon_list ';' statement_or_error
+ | semicolon_list ';'
+ ;
+statement_list : /* empty */
+ { $$ = 0; }
+ | statement
+ | statement_list ENDOFLINE
+ | statement_list ENDOFLINE statement
+ | statement_list ';'
+ | statement_list ';' statement
+ ;
+statement_or_error : statement
+ | error statement
+ { $$ = $2; }
+ ;
+statement : Warranty
+ { warranty("s"); }
+ | expression
+ {
+ if ($1 & 1)
+ generate ("W");
+ else
+ generate ("p");
+ }
+ | STRING
+ {
+ $$ = 0;
+ generate ("w");
+ generate ($1);
+ free ($1);
+ }
+ | Break
+ {
+ if (break_label == 0)
+ yyerror ("Break outside a for/while");
+ else
+ {
+ sprintf (genstr, "J%1d:", break_label);
+ generate (genstr);
+ }
+ }
+ | Quit
+ { exit(0); }
+ | Return
+ { generate ("0R"); }
+ | Return '(' return_expression ')'
+ { generate ("R"); }
+ | For
+ {
+ $1 = break_label;
+ break_label = next_label++;
+ }
+ '(' expression ';'
+ {
+ $4 = next_label++;
+ sprintf (genstr, "pN%1d:", $4);
+ generate (genstr);
+ }
+ relational_expression ';'
+ {
+ $7 = next_label++;
+ sprintf (genstr, "B%1d:J%1d:", $7, break_label);
+ generate (genstr);
+ $<i_value>$ = next_label++;
+ sprintf (genstr, "N%1d:", $<i_value>$);
+ generate (genstr);
+ }
+ expression ')'
+ {
+ sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
+ generate (genstr);
+ }
+ statement
+ {
+ sprintf (genstr, "J%1d:N%1d:", $<i_value>9,
+ break_label);
+ generate (genstr);
+ break_label = $1;
+ }
+ | If '(' relational_expression ')'
+ {
+ $3 = next_label++;
+ sprintf (genstr, "Z%1d:", $3);
+ generate (genstr);
+ }
+ statement
+ {
+ sprintf (genstr, "N%1d:", $3);
+ generate (genstr);
+ }
+ | While
+ {
+ $1 = next_label++;
+ sprintf (genstr, "N%1d:", $1);
+ generate (genstr);
+ }
+ '(' relational_expression
+ {
+ $4 = break_label;
+ break_label = next_label++;
+ sprintf (genstr, "Z%1d:", break_label);
+ generate (genstr);
+ }
+ ')' statement
+ {
+ sprintf (genstr, "J%1d:N%1d:", $1, break_label);
+ generate (genstr);
+ break_label = $4;
+ }
+ | '{' statement_list '}'
+ { $$ = 0; }
+ ;
+function : Define NAME '(' opt_parameter_list ')' '{'
+ ENDOFLINE opt_auto_define_list
+ {
+ check_params ($4,$8);
+ sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
+ arg_str ($4), arg_str ($8));
+ generate (genstr);
+ free_args ($4);
+ free_args ($8);
+ $1 = next_label;
+ next_label = 0;
+ }
+ statement_list ENDOFLINE '}'
+ {
+ generate ("0R]");
+ next_label = $1;
+ }
+ ;
+opt_parameter_list : /* empty */
+ { $$ = NULL; }
+ | parameter_list
+ ;
+parameter_list : NAME
+ { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); }
+ | define_list ',' NAME
+ { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); }
+ ;
+opt_auto_define_list : /* empty */
+ { $$ = NULL; }
+ | Auto define_list ENDOFLINE
+ { $$ = $2; }
+ | Auto define_list ';'
+ { $$ = $2; }
+ ;
+define_list : NAME
+ { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); }
+ | NAME '[' ']'
+ { $$ = nextarg (NULL, lookup($1,ARRAY), FALSE); }
+ | define_list ',' NAME
+ { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); }
+ | define_list ',' NAME '[' ']'
+ { $$ = nextarg ($1, lookup($3,ARRAY), FALSE); }
+ ;
+opt_argument_list : /* empty */
+ { $$ = NULL; }
+ | argument_list
+ ;
+argument_list : expression
+ { $$ = nextarg (NULL,0, FALSE); }
+ | argument_list ',' expression
+ { $$ = nextarg ($1,0, FALSE); }
+ ;
+relational_expression : expression
+ { $$ = 0; }
+ | expression REL_OP expression
+ {
+ $$ = 0;
+ switch (*($2))
+ {
+ case '=':
+ generate ("=");
+ break;
+ case '!':
+ generate ("#");
+ break;
+ case '<':
+ if ($2[1] == '=')
+ generate ("{");
+ else
+ generate ("<");
+ break;
+ case '>':
+ if ($2[1] == '=')
+ generate ("}");
+ else
+ generate (">");
+ break;
+ }
+ }
+ ;
+return_expression : /* empty */
+ {
+ $$ = 0;
+ generate ("0");
+ }
+ | expression
+ ;
+expression : named_expression ASSIGN_OP
+ {
+ if ($2 != '=')
+ {
+ if ($1 < 0)
+ sprintf (genstr, "DL%d:", -$1);
+ else
+ sprintf (genstr, "l%d:", $1);
+ generate (genstr);
+ }
+ }
+ expression
+ {
+ $$ = 0;
+ if ($2 != '=')
+ {
+ sprintf (genstr, "%c", $2);
+ generate (genstr);
+ }
+ if ($1 < 0)
+ sprintf (genstr, "S%d:", -$1);
+ else
+ sprintf (genstr, "s%d:", $1);
+ generate (genstr);
+ }
+ | expression '+' expression
+ { generate ("+"); }
+ | expression '-' expression
+ { generate ("-"); }
+ | expression '*' expression
+ { generate ("*"); }
+ | expression '/' expression
+ { generate ("/"); }
+ | expression '%' expression
+ { generate ("%"); }
+ | expression '^' expression
+ { generate ("^"); }
+ | '-' expression %prec UNARY_MINUS
+ { generate ("n"); $$ = 1;}
+ | named_expression
+ {
+ $$ = 1;
+ if ($1 < 0)
+ sprintf (genstr, "L%d:", -$1);
+ else
+ sprintf (genstr, "l%d:", $1);
+ generate (genstr);
+ }
+ | NUMBER
+ {
+ int len = strlen($1);
+ $$ = 1;
+ if (len == 1 && *$1 == '0')
+ generate ("0");
+ else
+ {
+ if (len == 1 && *$1 == '1')
+ generate ("1");
+ else
+ {
+ generate ("K");
+ generate ($1);
+ generate (":");
+ }
+ free ($1);
+ }
+ }
+ | '(' expression ')'
+ { $$ = 1; }
+ | NAME '(' opt_argument_list ')'
+ {
+ $$ = 1;
+ if ($3 != NULL)
+ {
+ sprintf (genstr, "C%d,%s:", lookup($1,FUNCT),
+ arg_str ($3));
+ free_args ($3);
+ }
+ else
+ sprintf (genstr, "C%d:", lookup($1,FUNCT));
+ generate (genstr);
+ }
+ | INCR_DECR named_expression
+ {
+ $$ = 1;
+ if ($2 < 0)
+ {
+ if ($1 == '+')
+ sprintf (genstr, "DA%d:L%d:", -$2, -$2);
+ else
+ sprintf (genstr, "DM%d:L%d:", -$2, -$2);
+ }
+ else
+ {
+ if ($1 == '+')
+ sprintf (genstr, "i%d:l%d:", $2, $2);
+ else
+ sprintf (genstr, "d%d:l%d:", $2, $2);
+ }
+ generate (genstr);
+ }
+ | named_expression INCR_DECR
+ {
+ $$ = 1;
+ if ($1 < 0)
+ {
+ sprintf (genstr, "DL%d:x", -$1);
+ generate (genstr);
+ if ($2 == '+')
+ sprintf (genstr, "A%d:", -$1);
+ else
+ sprintf (genstr, "M%d:", -$1);
+ }
+ else
+ {
+ sprintf (genstr, "l%d:", $1);
+ generate (genstr);
+ if ($2 == '+')
+ sprintf (genstr, "i%d:", $1);
+ else
+ sprintf (genstr, "d%d:", $1);
+ }
+ generate (genstr);
+ }
+ | Length '(' expression ')'
+ { generate ("cL"); $$ = 1;}
+ | Sqrt '(' expression ')'
+ { generate ("cR"); $$ = 1;}
+ | Scale '(' expression ')'
+ { generate ("cS"); $$ = 1;}
+ ;
+named_expression : NAME
+ { $$ = lookup($1,SIMPLE); }
+ | NAME '[' expression ']'
+ { $$ = lookup($1,ARRAY); }
+ | Ibase
+ { $$ = 0; }
+ | Obase
+ { $$ = 1; }
+ | Scale
+ { $$ = 2; }
+ ;
+
+%%