2
/* bc.y: The grammar for a POSIX compatable bc processor with some
3
extensions to the language. */
5
/* This file is part of GNU bc.
6
Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License , or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program; see the file COPYING. If not, write to:
20
The Free Software Foundation, Inc.
21
59 Temple Place, Suite 330
24
You may contact the author by:
25
e-mail: philnelson@acm.org
26
us-mail: Philip A. Nelson
27
Computer Science Department, 9062
28
Western Washington University
29
Bellingham, WA 98226-9062
31
*************************************************************************/
47
/* Extensions over POSIX bc.
48
a) NAME was LETTER. This grammar allows longer names.
49
Single letter names will still work.
50
b) Relational_expression allowed only one comparison.
51
This grammar has added boolean expressions with
52
&& (and) || (or) and ! (not) and allowed all of them in
54
c) Added an else to the if.
55
d) Call by variable array parameters
56
e) read() procedure that reads a number under program control from stdin.
57
f) halt statement that halts the the program under program control. It
58
is an executed statement.
59
g) continue statement for for loops.
60
h) optional expressions in the for loop.
61
i) print statement to print multiple numbers per line.
62
j) warranty statement to print an extended warranty notice.
63
j) limits statement to print the processor's limits.
66
%token <i_value> ENDOFLINE AND OR NOT
67
%token <s_value> STRING NAME NUMBER
68
/* '-', '+' are tokens themselves */
69
/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
70
%token <c_value> ASSIGN_OP
71
/* '==', '<=', '>=', '!=', '<', '>' */
72
%token <s_value> REL_OP
74
%token <c_value> INCR_DECR
75
/* 'define', 'break', 'quit', 'length' */
76
%token <i_value> Define Break Quit Length
77
/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
78
%token <i_value> Return For If While Sqrt Else
79
/* 'scale', 'ibase', 'obase', 'auto', 'read' */
80
%token <i_value> Scale Ibase Obase Auto Read
81
/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
82
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
84
%token <i_value> UNARY_MINUS HistoryVar
86
/* Types of all other things. */
87
%type <i_value> expression return_expression named_expression opt_expression
88
%type <c_value> '+' '-' '*' '/' '%'
89
%type <a_value> opt_parameter_list opt_auto_define_list define_list
90
%type <a_value> opt_argument_list argument_list
91
%type <i_value> program input_item semicolon_list statement_list
92
%type <i_value> statement function statement_or_error required_eol
103
%nonassoc UNARY_MINUS
107
program : /* empty */
110
if (interactive && !quiet)
118
input_item : semicolon_list ENDOFLINE
128
opt_newline : /* empty */
130
{ warn ("newline not allowed"); }
132
semicolon_list : /* empty */
135
| semicolon_list ';' statement_or_error
138
statement_list : /* empty */
141
| statement_list ENDOFLINE
142
| statement_list ENDOFLINE statement_or_error
144
| statement_list ';' statement
146
statement_or_error : statement
157
warn ("comparison in expression");
172
if (break_label == 0)
173
yyerror ("Break outside a for/while");
176
sprintf (genstr, "J%1d:", break_label);
182
warn ("Continue statement");
183
if (continue_label == 0)
184
yyerror ("Continue outside a for");
187
sprintf (genstr, "J%1d:", continue_label);
195
| Return return_expression
200
break_label = next_label++;
202
'(' opt_expression ';'
205
warn ("Comparison in first for expression");
209
sprintf (genstr, "N%1d:", $4);
214
if ($7 < 0) generate ("1");
216
sprintf (genstr, "B%1d:J%1d:", $7, break_label);
218
$<i_value>$ = continue_label;
219
continue_label = next_label++;
220
sprintf (genstr, "N%1d:", continue_label);
226
warn ("Comparison in third for expression");
228
sprintf (genstr, "J%1d:N%1d:", $4, $7);
230
sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
233
opt_newline statement
235
sprintf (genstr, "J%1d:N%1d:",
236
continue_label, break_label);
239
continue_label = $<i_value>9;
241
| If '(' expression ')'
244
if_label = next_label++;
245
sprintf (genstr, "Z%1d:", if_label);
248
opt_newline statement opt_else
250
sprintf (genstr, "N%1d:", if_label);
257
sprintf (genstr, "N%1d:", $1);
263
break_label = next_label++;
264
sprintf (genstr, "Z%1d:", break_label);
267
')' opt_newline statement
269
sprintf (genstr, "J%1d:N%1d:", $1, break_label);
273
| '{' statement_list '}'
276
{ warn ("print statement"); }
279
print_list : print_element
280
| print_element ',' print_list
282
print_element : STRING
291
opt_else : /* nothing */
294
warn ("else clause in if statement");
296
sprintf (genstr, "J%d:N%1d:", $1, if_label);
300
opt_newline statement
301
function : Define NAME '(' opt_parameter_list ')' opt_newline
302
'{' required_eol opt_auto_define_list
304
/* Check auto list against parameter list? */
305
check_params ($4,$9);
306
sprintf (genstr, "F%d,%s.%s[",
308
arg_str ($4), arg_str ($9));
315
statement_list /* ENDOFLINE */ '}'
321
opt_parameter_list : /* empty */
325
opt_auto_define_list : /* empty */
327
| Auto define_list ENDOFLINE
329
| Auto define_list ';'
333
{ $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);}
335
{ $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
337
{ $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); }
338
| define_list ',' NAME
339
{ $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
340
| define_list ',' NAME '[' ']'
341
{ $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
342
| define_list ',' '*' NAME '[' ']'
343
{ $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); }
345
opt_argument_list : /* empty */
349
argument_list : expression
351
if ($1 & 2) warn ("comparison in argument");
352
$$ = nextarg (NULL,0,FALSE);
356
sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
358
$$ = nextarg (NULL,1,FALSE);
360
| argument_list ',' expression
362
if ($3 & 2) warn ("comparison in argument");
363
$$ = nextarg ($1,0,FALSE);
365
| argument_list ',' NAME '[' ']'
367
sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
369
$$ = nextarg ($1,1,FALSE);
373
/* Expression lval meanings! (Bits mean something!)
374
* 0 => Top op is assignment.
375
* 1 => Top op is not assignment.
376
* 2 => Comparison is somewhere in expression.
377
* 4 => Expression is in parenthesis.
378
* 16 => Empty optional expression.
381
opt_expression : /* empty */
384
warn ("Missing expression in for statement");
388
return_expression : /* empty */
396
warn ("comparison in return expresion");
398
warn ("return expression requires parenthesis");
401
expression : named_expression ASSIGN_OP
406
sprintf (genstr, "DL%d:", -$1);
408
sprintf (genstr, "l%d:", $1);
414
if ($4 & 2) warn("comparison in assignment");
417
sprintf (genstr, "%c", $2);
421
sprintf (genstr, "S%d:", -$1);
423
sprintf (genstr, "s%d:", $1);
432
sprintf (genstr, "DZ%d:p", $2);
437
sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
445
sprintf (genstr, "B%d:", $2);
451
tmplab = next_label++;
452
sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
453
$2, tmplab, $2, tmplab);
463
| expression REL_OP expression
491
| expression '+' expression
496
| expression '-' expression
501
| expression '*' expression
506
| expression '/' expression
511
| expression '%' expression
516
| expression '^' expression
521
| '-' expression %prec UNARY_MINUS
530
sprintf (genstr, "L%d:", -$1);
532
sprintf (genstr, "l%d:", $1);
537
int len = strlen($1);
539
if (len == 1 && *$1 == '0')
541
else if (len == 1 && *$1 == '1')
553
| NAME '(' opt_argument_list ')'
558
sprintf (genstr, "C%d,%s:",
565
sprintf (genstr, "C%d:", lookup ($1,FUNCT));
569
| INCR_DECR named_expression
575
sprintf (genstr, "DA%d:L%d:", -$2, -$2);
577
sprintf (genstr, "DM%d:L%d:", -$2, -$2);
582
sprintf (genstr, "i%d:l%d:", $2, $2);
584
sprintf (genstr, "d%d:l%d:", $2, $2);
588
| named_expression INCR_DECR
593
sprintf (genstr, "DL%d:x", -$1);
596
sprintf (genstr, "A%d:", -$1);
598
sprintf (genstr, "M%d:", -$1);
602
sprintf (genstr, "l%d:", $1);
605
sprintf (genstr, "i%d:", $1);
607
sprintf (genstr, "d%d:", $1);
611
| Length '(' expression ')'
612
{ generate ("cL"); $$ = 1;}
613
| Sqrt '(' expression ')'
614
{ generate ("cR"); $$ = 1;}
615
| Scale '(' expression ')'
616
{ generate ("cS"); $$ = 1;}
619
warn ("read function");
620
generate ("cI"); $$ = 1;
623
named_expression : NAME
624
{ $$ = lookup($1,SIMPLE); }
625
| NAME '[' expression ']'
627
if ($3 > 1) warn("comparison in subscript");
628
$$ = lookup($1,ARRAY);
638
warn ("History variable");
642
warn ("Last variable");
647
required_eol : { warn ("End of line required"); }
649
| required_eol ENDOFLINE
650
{ warn ("Too many end of lines"); }