source: trunk/minix/commands/bc/bc.y@ 10

Last change on this file since 10 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 14.5 KB
Line 
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, 1992 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 <i_value> program input_item semicolon_list statement_list
90%type <i_value> statement function statement_or_error
91
92/* precedence */
93%left OR
94%left AND
95%nonassoc NOT
96%left REL_OP
97%right ASSIGN_OP
98%left '+' '-'
99%left MUL_OP
100%right '^'
101%nonassoc UNARY_MINUS
102%nonassoc INCR_DECR
103
104%%
105program : /* empty */
106 {
107 $$ = 0;
108 if (interactive)
109 {
110 printf ("%s\n", BC_VERSION);
111 welcome ();
112 }
113 }
114 | program input_item
115 ;
116input_item : semicolon_list NEWLINE
117 { run_code (); }
118 | function
119 { run_code (); }
120 | error NEWLINE
121 {
122 yyerrok;
123 init_gen ();
124 }
125 ;
126semicolon_list : /* empty */
127 { $$ = 0; }
128 | statement_or_error
129 | semicolon_list ';' statement_or_error
130 | semicolon_list ';'
131 ;
132statement_list : /* empty */
133 { $$ = 0; }
134 | statement_or_error
135 | statement_list NEWLINE
136 | statement_list NEWLINE statement_or_error
137 | statement_list ';'
138 | statement_list ';' statement
139 ;
140statement_or_error : statement
141 | error statement
142 { $$ = $2; }
143 ;
144statement : Warranty
145 { warranty (""); }
146 | Limits
147 { limits (); }
148 | expression
149 {
150 if ($1 & 2)
151 warn ("comparison in expression");
152 if ($1 & 1)
153 generate ("W");
154 else
155 generate ("p");
156 }
157 | STRING
158 {
159 $$ = 0;
160 generate ("w");
161 generate ($1);
162 free ($1);
163 }
164 | Break
165 {
166 if (break_label == 0)
167 yyerror ("Break outside a for/while");
168 else
169 {
170 sprintf (genstr, "J%1d:", break_label);
171 generate (genstr);
172 }
173 }
174 | Continue
175 {
176 warn ("Continue statement");
177 if (continue_label == 0)
178 yyerror ("Continue outside a for");
179 else
180 {
181 sprintf (genstr, "J%1d:", continue_label);
182 generate (genstr);
183 }
184 }
185 | Quit
186 { exit (0); }
187 | Halt
188 { generate ("h"); }
189 | Return
190 { generate ("0R"); }
191 | Return '(' return_expression ')'
192 { generate ("R"); }
193 | For
194 {
195 $1 = break_label;
196 break_label = next_label++;
197 }
198 '(' opt_expression ';'
199 {
200 if ($4 > 1)
201 warn ("Comparison in first for expression");
202 $4 = next_label++;
203 if ($4 < 0)
204 sprintf (genstr, "N%1d:", $4);
205 else
206 sprintf (genstr, "pN%1d:", $4);
207 generate (genstr);
208 }
209 opt_expression ';'
210 {
211 if ($7 < 0) generate ("1");
212 $7 = next_label++;
213 sprintf (genstr, "B%1d:J%1d:", $7, break_label);
214 generate (genstr);
215 $<i_value>$ = continue_label;
216 continue_label = next_label++;
217 sprintf (genstr, "N%1d:", continue_label);
218 generate (genstr);
219 }
220 opt_expression ')'
221 {
222 if ($10 > 1)
223 warn ("Comparison in third for expression");
224 if ($10 < 0)
225 sprintf (genstr, "J%1d:N%1d:", $4, $7);
226 else
227 sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
228 generate (genstr);
229 }
230 statement
231 {
232 sprintf (genstr, "J%1d:N%1d:",
233 continue_label, break_label);
234 generate (genstr);
235 break_label = $1;
236 continue_label = $<i_value>9;
237 }
238 | If '(' expression ')'
239 {
240 $3 = if_label;
241 if_label = next_label++;
242 sprintf (genstr, "Z%1d:", if_label);
243 generate (genstr);
244 }
245 statement opt_else
246 {
247 sprintf (genstr, "N%1d:", if_label);
248 generate (genstr);
249 if_label = $3;
250 }
251 | While
252 {
253 $1 = next_label++;
254 sprintf (genstr, "N%1d:", $1);
255 generate (genstr);
256 }
257 '(' expression
258 {
259 $4 = break_label;
260 break_label = next_label++;
261 sprintf (genstr, "Z%1d:", break_label);
262 generate (genstr);
263 }
264 ')' statement
265 {
266 sprintf (genstr, "J%1d:N%1d:", $1, break_label);
267 generate (genstr);
268 break_label = $4;
269 }
270 | '{' statement_list '}'
271 { $$ = 0; }
272 | Print
273 { warn ("print statement"); }
274 print_list
275 ;
276print_list : print_element
277 | print_element ',' print_list
278 ;
279print_element : STRING
280 {
281 generate ("O");
282 generate ($1);
283 free ($1);
284 }
285 | expression
286 { generate ("P"); }
287 ;
288opt_else : /* nothing */
289 | Else
290 {
291 warn ("else clause in if statement");
292 $1 = next_label++;
293 sprintf (genstr, "J%d:N%1d:", $1, if_label);
294 generate (genstr);
295 if_label = $1;
296 }
297 statement
298function : Define NAME '(' opt_parameter_list ')' '{'
299 NEWLINE opt_auto_define_list
300 {
301 /* Check auto list against parameter list? */
302 check_params ($4,$8);
303 sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT),
304 arg_str ($4,TRUE), arg_str ($8,TRUE));
305 generate (genstr);
306 free_args ($4);
307 free_args ($8);
308 $1 = next_label;
309 next_label = 0;
310 }
311 statement_list NEWLINE '}'
312 {
313 generate ("0R]");
314 next_label = $1;
315 }
316 ;
317opt_parameter_list : /* empty */
318 { $$ = NULL; }
319 | define_list
320 ;
321opt_auto_define_list : /* empty */
322 { $$ = NULL; }
323 | Auto define_list NEWLINE
324 { $$ = $2; }
325 | Auto define_list ';'
326 { $$ = $2; }
327 ;
328define_list : NAME
329 { $$ = nextarg (NULL, lookup ($1,SIMPLE)); }
330 | NAME '[' ']'
331 { $$ = nextarg (NULL, lookup ($1,ARRAY)); }
332 | define_list ',' NAME
333 { $$ = nextarg ($1, lookup ($3,SIMPLE)); }
334 | define_list ',' NAME '[' ']'
335 { $$ = nextarg ($1, lookup ($3,ARRAY)); }
336 ;
337opt_argument_list : /* empty */
338 { $$ = NULL; }
339 | argument_list
340 ;
341argument_list : expression
342 {
343 if ($1 > 1) warn ("comparison in argument");
344 $$ = nextarg (NULL,0);
345 }
346 | NAME '[' ']'
347 {
348 sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
349 generate (genstr);
350 $$ = nextarg (NULL,1);
351 }
352 | argument_list ',' expression
353 {
354 if ($3 > 1) warn ("comparison in argument");
355 $$ = nextarg ($1,0);
356 }
357 | argument_list ',' NAME '[' ']'
358 {
359 sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
360 generate (genstr);
361 $$ = nextarg ($1,1);
362 }
363 ;
364opt_expression : /* empty */
365 {
366 $$ = -1;
367 warn ("Missing expression in for statement");
368 }
369 | expression
370 ;
371return_expression : /* empty */
372 {
373 $$ = 0;
374 generate ("0");
375 }
376 | expression
377 {
378 if ($1 > 1)
379 warn ("comparison in return expresion");
380 }
381 ;
382expression : named_expression ASSIGN_OP
383 {
384 if ($2 != '=')
385 {
386 if ($1 < 0)
387 sprintf (genstr, "DL%d:", -$1);
388 else
389 sprintf (genstr, "l%d:", $1);
390 generate (genstr);
391 }
392 }
393 expression
394 {
395 if ($4 > 1) warn("comparison in assignment");
396 if ($2 != '=')
397 {
398 sprintf (genstr, "%c", $2);
399 generate (genstr);
400 }
401 if ($1 < 0)
402 sprintf (genstr, "S%d:", -$1);
403 else
404 sprintf (genstr, "s%d:", $1);
405 generate (genstr);
406 $$ = 0;
407 }
408 ;
409 | expression AND
410 {
411 warn("&& operator");
412 $2 = next_label++;
413 sprintf (genstr, "DZ%d:p", $2);
414 generate (genstr);
415 }
416 expression
417 {
418 sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
419 generate (genstr);
420 $$ = $1 | $4;
421 }
422 | expression OR
423 {
424 warn("|| operator");
425 $2 = next_label++;
426 sprintf (genstr, "B%d:", $2);
427 generate (genstr);
428 }
429 expression
430 {
431 int tmplab;
432 tmplab = next_label++;
433 sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
434 $2, tmplab, $2, tmplab);
435 generate (genstr);
436 $$ = $1 | $4;
437 }
438 | NOT expression
439 {
440 $$ = $2;
441 warn("! operator");
442 generate ("!");
443 }
444 | expression REL_OP expression
445 {
446 $$ = 3;
447 switch (*($2))
448 {
449 case '=':
450 generate ("=");
451 break;
452
453 case '!':
454 generate ("#");
455 break;
456
457 case '<':
458 if ($2[1] == '=')
459 generate ("{");
460 else
461 generate ("<");
462 break;
463
464 case '>':
465 if ($2[1] == '=')
466 generate ("}");
467 else
468 generate (">");
469 break;
470 }
471 }
472 | expression '+' expression
473 {
474 generate ("+");
475 $$ = $1 | $3;
476 }
477 | expression '-' expression
478 {
479 generate ("-");
480 $$ = $1 | $3;
481 }
482 | expression MUL_OP expression
483 {
484 genstr[0] = $2;
485 genstr[1] = 0;
486 generate (genstr);
487 $$ = $1 | $3;
488 }
489 | expression '^' expression
490 {
491 generate ("^");
492 $$ = $1 | $3;
493 }
494 | '-' expression %prec UNARY_MINUS
495 {
496 generate ("n");
497 $$ = $2;
498 }
499 | named_expression
500 {
501 $$ = 1;
502 if ($1 < 0)
503 sprintf (genstr, "L%d:", -$1);
504 else
505 sprintf (genstr, "l%d:", $1);
506 generate (genstr);
507 }
508 | NUMBER
509 {
510 int len = strlen($1);
511 $$ = 1;
512 if (len == 1 && *$1 == '0')
513 generate ("0");
514 else if (len == 1 && *$1 == '1')
515 generate ("1");
516 else
517 {
518 generate ("K");
519 generate ($1);
520 generate (":");
521 }
522 free ($1);
523 }
524 | '(' expression ')'
525 { $$ = $2 | 1; }
526 | NAME '(' opt_argument_list ')'
527 {
528 $$ = 1;
529 if ($3 != NULL)
530 {
531 sprintf (genstr, "C%d,%s:",
532 lookup ($1,FUNCT),
533 arg_str ($3,FALSE));
534 free_args ($3);
535 }
536 else
537 {
538 sprintf (genstr, "C%d:", lookup ($1,FUNCT));
539 }
540 generate (genstr);
541 }
542 | INCR_DECR named_expression
543 {
544 $$ = 1;
545 if ($2 < 0)
546 {
547 if ($1 == '+')
548 sprintf (genstr, "DA%d:L%d:", -$2, -$2);
549 else
550 sprintf (genstr, "DM%d:L%d:", -$2, -$2);
551 }
552 else
553 {
554 if ($1 == '+')
555 sprintf (genstr, "i%d:l%d:", $2, $2);
556 else
557 sprintf (genstr, "d%d:l%d:", $2, $2);
558 }
559 generate (genstr);
560 }
561 | named_expression INCR_DECR
562 {
563 $$ = 1;
564 if ($1 < 0)
565 {
566 sprintf (genstr, "DL%d:x", -$1);
567 generate (genstr);
568 if ($2 == '+')
569 sprintf (genstr, "A%d:", -$1);
570 else
571 sprintf (genstr, "M%d:", -$1);
572 }
573 else
574 {
575 sprintf (genstr, "l%d:", $1);
576 generate (genstr);
577 if ($2 == '+')
578 sprintf (genstr, "i%d:", $1);
579 else
580 sprintf (genstr, "d%d:", $1);
581 }
582 generate (genstr);
583 }
584 | Length '(' expression ')'
585 { generate ("cL"); $$ = 1;}
586 | Sqrt '(' expression ')'
587 { generate ("cR"); $$ = 1;}
588 | Scale '(' expression ')'
589 { generate ("cS"); $$ = 1;}
590 | Read '(' ')'
591 {
592 warn ("read function");
593 generate ("cI"); $$ = 1;
594 }
595 ;
596named_expression : NAME
597 { $$ = lookup($1,SIMPLE); }
598 | NAME '[' expression ']'
599 {
600 if ($3 > 1) warn("comparison in subscript");
601 $$ = lookup($1,ARRAY);
602 }
603 | Ibase
604 { $$ = 0; }
605 | Obase
606 { $$ = 1; }
607 | Scale
608 { $$ = 2; }
609 | Last
610 { $$ = 3; }
611 ;
612%%
Note: See TracBrowser for help on using the repository browser.