386BSD 0.1 development
[unix-history] / usr / othersrc / public / bc-1.01 / bc.y
CommitLineData
f87489ac
WJ
1%{
2/* bc.y: The grammar for a POSIX compatable bc processor with some
3 extensions to the language. */
4
5/* This file is part of bc written for MINIX.
6 Copyright (C) 1991 Free Software Foundation, Inc.
7
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.
12
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.
17
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, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 You may contact the author by:
23 e-mail: phil@cs.wwu.edu
24 us-mail: Philip A. Nelson
25 Computer Science Department, 9062
26 Western Washington University
27 Bellingham, WA 98226-9062
28
29*************************************************************************/
30
31#include "bcdefs.h"
32#include "global.h"
33#include "proto.h"
34%}
35
36%start program
37
38%union {
39 char *s_value;
40 char c_value;
41 int i_value;
42 arg_list *a_value;
43 }
44
45/* Extensions over POSIX bc.
46 a) NAME was LETTER. This grammer allows longer names.
47 Single letter names will still work.
48 b) Relational_expression allowed only one comparison.
49 This grammar has added boolean expressions with
50 && (and) || (or) and ! (not) and allowed all of them in
51 full expressions.
52 c) Added an else to the if.
53 d) Call by variable array parameters
54 e) read() procedure that reads a number under program control from stdin.
55 f) halt statement that halts the the program under program control. It
56 is an executed statement.
57 g) continue statement for for loops.
58 h) optional expressions in the for loop.
59 i) print statement to print multiple numbers per line.
60 j) warranty statement to print an extended warranty notice.
61 j) limits statement to print the processor's limits.
62*/
63
64%token <i_value> NEWLINE AND OR NOT
65%token <s_value> STRING NAME NUMBER
66/* '-', '+' are tokens themselves */
67%token <c_value> MUL_OP
68/* '*', '/', '%' */
69%token <c_value> ASSIGN_OP
70/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */
71%token <s_value> REL_OP
72/* '==', '<=', '>=', '!=', '<', '>' */
73%token <c_value> INCR_DECR
74/* '++', '--' */
75%token <i_value> Define Break Quit Length
76/* 'define', 'break', 'quit', 'length' */
77%token <i_value> Return For If While Sqrt Else
78/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */
79%token <i_value> Scale Ibase Obase Auto Read
80/* 'scale', 'ibase', 'obase', 'auto', 'read' */
81%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
82/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */
83
84/* Types of all other things. */
85%type <i_value> expression return_expression named_expression opt_expression
86%type <c_value> '+' '-'
87%type <a_value> opt_parameter_list opt_auto_define_list define_list
88%type <a_value> opt_argument_list argument_list
89%type <s_value> NAME STRING NUMBER
90%type <i_value> program input_item semicolon_list statement_list
91%type <i_value> statement function statement_or_error
92%type <i_value> NEWLINE AND OR NOT
93
94/* precedence */
95%left OR
96%left AND
97%nonassoc NOT
98%left REL_OP
99%right ASSIGN_OP
100%left '+' '-'
101%left MUL_OP
102%right '^'
103%nonassoc UNARY_MINUS
104%nonassoc INCR_DECR
105
106%%
107program : /* empty */
108 {
109 $$ = 0;
110 if (interactive)
111 {
112 printf ("%s\n", BC_VERSION);
113 welcome ();
114 }
115 }
116 | program input_item
117 ;
118input_item : semicolon_list NEWLINE
119 { run_code (); }
120 | function
121 { run_code (); }
122 | error NEWLINE
123 {
124 yyerrok;
125 init_gen ();
126 }
127 ;
128semicolon_list : /* empty */
129 { $$ = 0; }
130 | statement_or_error
131 | semicolon_list ';' statement_or_error
132 | semicolon_list ';'
133 ;
134statement_list : /* empty */
135 { $$ = 0; }
136 | statement_or_error
137 | statement_list NEWLINE
138 | statement_list NEWLINE statement_or_error
139 | statement_list ';'
140 | statement_list ';' statement
141 ;
142statement_or_error : statement
143 | error statement
144 { $$ = $2; }
145 ;
146statement : Warranty
147 { warranty (""); }
148 | Limits
149 { limits (); }
150 | expression
151 {
152 if ($1 & 2)
153 warn ("comparison in expression");
154 if ($1 & 1)
155 generate ("W");
156 else
157 generate ("p");
158 }
159 | STRING
160 {
161 $$ = 0;
162 generate ("w");
163 generate ($1);
164 free ($1);
165 }
166 | Break
167 {
168 if (break_label == 0)
169 yyerror ("Break outside a for/while");
170 else
171 {
172 sprintf (genstr, "J%1d:", break_label);
173 generate (genstr);
174 }
175 }
176 | Continue
177 {
178 warn ("Continue statement");
179 if (continue_label == 0)
180 yyerror ("Continue outside a for");
181 else
182 {
183 sprintf (genstr, "J%1d:", continue_label);
184 generate (genstr);
185 }
186 }
187 | Quit
188 { exit (0); }
189 | Halt
190 { generate ("h"); }
191 | Return
192 { generate ("0R"); }
193 | Return '(' return_expression ')'
194 { generate ("R"); }
195 | For
196 {
197 $1 = break_label;
198 break_label = next_label++;
199 }
200 '(' opt_expression ';'
201 {
202 if ($4 > 1)
203 warn ("Comparison in first for expression");
204 $4 = next_label++;
205 if ($4 < 0)
206 sprintf (genstr, "N%1d:", $4);
207 else
208 sprintf (genstr, "pN%1d:", $4);
209 generate (genstr);
210 }
211 opt_expression ';'
212 {
213 if ($7 < 0) generate ("1");
214 $7 = next_label++;
215 sprintf (genstr, "B%1d:J%1d:", $7, break_label);
216 generate (genstr);
217 $<i_value>$ = continue_label;
218 continue_label = next_label++;
219 sprintf (genstr, "N%1d:", continue_label);
220 generate (genstr);
221 }
222 opt_expression ')'
223 {
224 if ($10 > 1)
225 warn ("Comparison in third for expression");
226 if ($10 < 0)
227 sprintf (genstr, "J%1d:N%1d:", $4, $7);
228 else
229 sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
230 generate (genstr);
231 }
232 statement
233 {
234 sprintf (genstr, "J%1d:N%1d:",
235 continue_label, break_label);
236 generate (genstr);
237 break_label = $1;
238 continue_label = $<i_value>9;
239 }
240 | If '(' expression ')'
241 {
242 $3 = if_label;
243 if_label = next_label++;
244 sprintf (genstr, "Z%1d:", if_label);
245 generate (genstr);
246 }
247 statement opt_else
248 {
249 sprintf (genstr, "N%1d:", if_label);
250 generate (genstr);
251 if_label = $3;
252 }
253 | While
254 {
255 $1 = next_label++;
256 sprintf (genstr, "N%1d:", $1);
257 generate (genstr);
258 }
259 '(' expression
260 {
261 $4 = break_label;
262 break_label = next_label++;
263 sprintf (genstr, "Z%1d:", break_label);
264 generate (genstr);
265 }
266 ')' statement
267 {
268 sprintf (genstr, "J%1d:N%1d:", $1, break_label);
269 generate (genstr);
270 break_label = $4;
271 }
272 | '{' statement_list '}'
273 { $$ = 0; }
274 | Print
275 { warn ("print statement"); }
276 print_list
277 ;
278print_list : print_element
279 | print_element ',' print_list
280 ;
281print_element : STRING
282 {
283 generate ("O");
284 generate ($1);
285 free ($1);
286 }
287 | expression
288 { generate ("P"); }
289 ;
290opt_else : /* nothing */
291 | Else
292 {
293 warn ("else clause in if statement");
294 $1 = next_label++;
295 sprintf (genstr, "J%d:N%1d:", $1, if_label);
296 generate (genstr);
297 if_label = $1;
298 }
299 statement
300function : Define NAME '(' opt_parameter_list ')' '{'
301 NEWLINE opt_auto_define_list
302 {
303 /* Check auto list against parameter list? */
304 check_params ($4,$8);
305 sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
306 arg_str ($4,TRUE), arg_str ($8,TRUE));
307 generate (genstr);
308 free_args ($4);
309 free_args ($8);
310 $1 = next_label;
311 next_label = 0;
312 }
313 statement_list NEWLINE '}'
314 {
315 generate ("0R]");
316 next_label = $1;
317 }
318 ;
319opt_parameter_list : /* empty */
320 { $$ = NULL; }
321 | define_list
322 ;
323opt_auto_define_list : /* empty */
324 { $$ = NULL; }
325 | Auto define_list NEWLINE
326 { $$ = $2; }
327 | Auto define_list ';'
328 { $$ = $2; }
329 ;
330define_list : NAME
331 { $$ = nextarg (NULL, lookup ($1,SIMPLE)); }
332 | NAME '[' ']'
333 { $$ = nextarg (NULL, lookup ($1,ARRAY)); }
334 | define_list ',' NAME
335 { $$ = nextarg ($1, lookup ($3,SIMPLE)); }
336 | define_list ',' NAME '[' ']'
337 { $$ = nextarg ($1, lookup ($3,ARRAY)); }
338 ;
339opt_argument_list : /* empty */
340 { $$ = NULL; }
341 | argument_list
342 ;
343argument_list : expression
344 {
345 if ($1 > 1) warn ("comparison in argument");
346 $$ = nextarg (NULL,0);
347 }
348 | NAME '[' ']'
349 {
350 sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
351 generate (genstr);
352 $$ = nextarg (NULL,1);
353 }
354 | argument_list ',' expression
355 {
356 if ($3 > 1) warn ("comparison in argument");
357 $$ = nextarg ($1,0);
358 }
359 | argument_list ',' NAME '[' ']'
360 {
361 sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
362 generate (genstr);
363 $$ = nextarg ($1,1);
364 }
365 ;
366opt_expression : /* empty */
367 {
368 $$ = -1;
369 warn ("Missing expression in for statement");
370 }
371 | expression
372 ;
373return_expression : /* empty */
374 {
375 $$ = 0;
376 generate ("0");
377 }
378 | expression
379 {
380 if ($1 > 1)
381 warn ("comparison in return expresion");
382 }
383 ;
384expression : named_expression ASSIGN_OP
385 {
386 if ($2 != '=')
387 {
388 if ($1 < 0)
389 sprintf (genstr, "DL%d:", -$1);
390 else
391 sprintf (genstr, "l%d:", $1);
392 generate (genstr);
393 }
394 }
395 expression
396 {
397 if ($4 > 1) warn("comparison in assignment");
398 if ($2 != '=')
399 {
400 sprintf (genstr, "%c", $2);
401 generate (genstr);
402 }
403 if ($1 < 0)
404 sprintf (genstr, "S%d:", -$1);
405 else
406 sprintf (genstr, "s%d:", $1);
407 generate (genstr);
408 $$ = 0;
409 }
410 ;
411 | expression AND
412 {
413 warn("&& operator");
414 $2 = next_label++;
415 sprintf (genstr, "DZ%d:p", $2);
416 generate (genstr);
417 }
418 expression
419 {
420 sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
421 generate (genstr);
422 $$ = $1 | $4;
423 }
424 | expression OR
425 {
426 warn("|| operator");
427 $2 = next_label++;
428 sprintf (genstr, "B%d:", $2);
429 generate (genstr);
430 }
431 expression
432 {
433 int tmplab;
434 tmplab = next_label++;
435 sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
436 $2, tmplab, $2, tmplab);
437 generate (genstr);
438 $$ = $1 | $4;
439 }
440 | NOT expression
441 {
442 $$ = $2;
443 warn("! operator");
444 generate ("!");
445 }
446 | expression REL_OP expression
447 {
448 $$ = 3;
449 switch (*($2))
450 {
451 case '=':
452 generate ("=");
453 break;
454
455 case '!':
456 generate ("#");
457 break;
458
459 case '<':
460 if ($2[1] == '=')
461 generate ("{");
462 else
463 generate ("<");
464 break;
465
466 case '>':
467 if ($2[1] == '=')
468 generate ("}");
469 else
470 generate (">");
471 break;
472 }
473 }
474 | expression '+' expression
475 {
476 generate ("+");
477 $$ = $1 | $3;
478 }
479 | expression '-' expression
480 {
481 generate ("-");
482 $$ = $1 | $3;
483 }
484 | expression MUL_OP expression
485 {
486 genstr[0] = $2;
487 genstr[1] = 0;
488 generate (genstr);
489 $$ = $1 | $3;
490 }
491 | expression '^' expression
492 {
493 generate ("^");
494 $$ = $1 | $3;
495 }
496 | '-' expression %prec UNARY_MINUS
497 {
498 generate ("n");
499 $$ = $2;
500 }
501 | named_expression
502 {
503 $$ = 1;
504 if ($1 < 0)
505 sprintf (genstr, "L%d:", -$1);
506 else
507 sprintf (genstr, "l%d:", $1);
508 generate (genstr);
509 }
510 | NUMBER
511 {
512 int len = strlen($1);
513 $$ = 1;
514 if (len == 1 && *$1 == '0')
515 generate ("0");
516 else if (len == 1 && *$1 == '1')
517 generate ("1");
518 else
519 {
520 generate ("K");
521 generate ($1);
522 generate (":");
523 }
524 free ($1);
525 }
526 | '(' expression ')'
527 { $$ = $2 | 1; }
528 | NAME '(' opt_argument_list ')'
529 {
530 $$ = 1;
531 if ($3 != NULL)
532 {
533 sprintf (genstr, "C%d,%s:",
534 lookup ($1,FUNCT),
535 arg_str ($3,FALSE));
536 free_args ($3);
537 }
538 else
539 {
540 sprintf (genstr, "C%d:", lookup ($1,FUNCT));
541 }
542 generate (genstr);
543 }
544 | INCR_DECR named_expression
545 {
546 $$ = 1;
547 if ($2 < 0)
548 {
549 if ($1 == '+')
550 sprintf (genstr, "DA%d:L%d:", -$2, -$2);
551 else
552 sprintf (genstr, "DM%d:L%d:", -$2, -$2);
553 }
554 else
555 {
556 if ($1 == '+')
557 sprintf (genstr, "i%d:l%d:", $2, $2);
558 else
559 sprintf (genstr, "d%d:l%d:", $2, $2);
560 }
561 generate (genstr);
562 }
563 | named_expression INCR_DECR
564 {
565 $$ = 1;
566 if ($1 < 0)
567 {
568 sprintf (genstr, "DL%d:x", -$1);
569 generate (genstr);
570 if ($2 == '+')
571 sprintf (genstr, "A%d:", -$1);
572 else
573 sprintf (genstr, "M%d:", -$1);
574 }
575 else
576 {
577 sprintf (genstr, "l%d:", $1);
578 generate (genstr);
579 if ($2 == '+')
580 sprintf (genstr, "i%d:", $1);
581 else
582 sprintf (genstr, "d%d:", $1);
583 }
584 generate (genstr);
585 }
586 | Length '(' expression ')'
587 { generate ("cL"); $$ = 1;}
588 | Sqrt '(' expression ')'
589 { generate ("cR"); $$ = 1;}
590 | Scale '(' expression ')'
591 { generate ("cS"); $$ = 1;}
592 | Read '(' ')'
593 {
594 warn ("read function");
595 generate ("cI"); $$ = 1;
596 }
597 ;
598named_expression : NAME
599 { $$ = lookup($1,SIMPLE); }
600 | NAME '[' expression ']'
601 {
602 if ($3 > 1) warn("comparison in subscript");
603 $$ = lookup($1,ARRAY);
604 }
605 | Ibase
606 { $$ = 0; }
607 | Obase
608 { $$ = 1; }
609 | Scale
610 { $$ = 2; }
611 | Last
612 { $$ = 3; }
613 ;
614%%