449 lines
11 KiB
Plaintext
449 lines
11 KiB
Plaintext
, %{
|
|
/* sbc.y: A POSIX bc processor written for minix with no extensions. */
|
|
|
|
/* This file is part of bc written for MINIX.
|
|
Copyright (C) 1991, 1992 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:
|
|
e-mail: phil@cs.wwu.edu
|
|
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> NEWLINE AND OR NOT
|
|
%token <s_value> STRING NAME NUMBER
|
|
/* '-', '+' are tokens themselves */
|
|
%token <c_value> MUL_OP
|
|
/* '*', '/', '%' */
|
|
%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 MUL_OP
|
|
%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 NEWLINE
|
|
{ run_code(); }
|
|
| function
|
|
{ run_code(); }
|
|
| error NEWLINE
|
|
{
|
|
yyerrok;
|
|
init_gen() ;
|
|
}
|
|
;
|
|
semicolon_list : /* empty */
|
|
{ $$ = 0; }
|
|
| statement_or_error
|
|
| semicolon_list ';' statement_or_error
|
|
| semicolon_list ';'
|
|
;
|
|
statement_list : /* empty */
|
|
{ $$ = 0; }
|
|
| statement
|
|
| statement_list NEWLINE
|
|
| statement_list NEWLINE 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 ')' '{'
|
|
NEWLINE opt_auto_define_list
|
|
{
|
|
check_params ($4,$8);
|
|
sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
|
|
arg_str ($4,TRUE), arg_str ($8,TRUE));
|
|
generate (genstr);
|
|
free_args ($4);
|
|
free_args ($8);
|
|
$1 = next_label;
|
|
next_label = 0;
|
|
}
|
|
statement_list NEWLINE '}'
|
|
{
|
|
generate ("0R]");
|
|
next_label = $1;
|
|
}
|
|
;
|
|
opt_parameter_list : /* empty */
|
|
{ $$ = NULL; }
|
|
| parameter_list
|
|
;
|
|
parameter_list : NAME
|
|
{ $$ = nextarg (NULL, lookup($1,SIMPLE)); }
|
|
| define_list ',' NAME
|
|
{ $$ = nextarg ($1, lookup($3,SIMPLE)); }
|
|
;
|
|
opt_auto_define_list : /* empty */
|
|
{ $$ = NULL; }
|
|
| Auto define_list NEWLINE
|
|
{ $$ = $2; }
|
|
| Auto define_list ';'
|
|
{ $$ = $2; }
|
|
;
|
|
define_list : NAME
|
|
{ $$ = nextarg (NULL, lookup($1,SIMPLE)); }
|
|
| NAME '[' ']'
|
|
{ $$ = nextarg (NULL, lookup($1,ARRAY)); }
|
|
| define_list ',' NAME
|
|
{ $$ = nextarg ($1, lookup($3,SIMPLE)); }
|
|
| define_list ',' NAME '[' ']'
|
|
{ $$ = nextarg ($1, lookup($3,ARRAY)); }
|
|
;
|
|
opt_argument_list : /* empty */
|
|
{ $$ = NULL; }
|
|
| argument_list
|
|
;
|
|
argument_list : expression
|
|
{ $$ = nextarg (NULL,0); }
|
|
| argument_list ',' expression
|
|
{ $$ = nextarg ($1,0); }
|
|
;
|
|
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 MUL_OP expression
|
|
{
|
|
genstr[0] = $2;
|
|
genstr[1] = 0;
|
|
generate (genstr);
|
|
}
|
|
| 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,FALSE));
|
|
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; }
|
|
;
|
|
|
|
%%
|