1 %{
2 /* sbc.y: A POSIX bc processor written for minix with no extensions.  */
3 
4 /*  This file is part of GNU bc.
5     Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License , or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; see the file COPYING.  If not, write to
19       The Free Software Foundation, Inc.
20       51 Franklin Street, Fifth Floor
21       Boston, MA 02110-1301  USA
22 
23 
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
30 
31 *************************************************************************/
32 
33 #include "bcdefs.h"
34 #include "global.h"     /* To get the global variables. */
35 #include "proto.h"
36 %}
37 
38 %start program
39 
40 %union {
41 	char *s_value;
42 	char  c_value;
43 	int   i_value;
44 	arg_list *a_value;
45        }
46 
47 %token <i_value> ENDOFLINE AND OR NOT
48 %token <s_value> STRING NAME NUMBER
49 /*     '-', '+' are tokens themselves		*/
50 %token <c_value> ASSIGN_OP
51 /*     '=', '+=',  '-=', '*=', '/=', '%=', '^=' */
52 %token <s_value> REL_OP
53 /*     '==', '<=', '>=', '!=', '<', '>' 	*/
54 %token <c_value> INCR_DECR
55 /*     '++', '--' 				*/
56 %token <i_value> Define    Break    Quit    Length
57 /*     'define', 'break', 'quit', 'length' 	*/
58 %token <i_value> Return    For    If    While    Sqrt  Else
59 /*     'return', 'for', 'if', 'while', 'sqrt',  'else' 	*/
60 %token <i_value> Scale    Ibase    Obase    Auto  Read
61 /*     'scale', 'ibase', 'obase', 'auto', 'read' 	*/
62 %token <i_value> Warranty, Halt, Last, Continue, Print, Limits
63 /*     'warranty', 'halt', 'last', 'continue', 'print', 'limits'  */
64 
65 /* The types of all other non-terminals. */
66 %type <i_value> expression named_expression return_expression
67 %type <a_value> opt_parameter_list parameter_list opt_auto_define_list
68 %type <a_value> define_list opt_argument_list argument_list
69 %type <i_value> program input_item semicolon_list statement_list
70 %type <i_value> statement_or_error statement function relational_expression
71 
72 /* precedence */
73 %nonassoc REL_OP
74 %right ASSIGN_OP
75 %left '+' '-'
76 %left '*' '/' '%'
77 %right '^'
78 %nonassoc UNARY_MINUS
79 %nonassoc INCR_DECR
80 
81 %%
82 program			: /* empty */
83 			    {
84 			      $$ = 0;
85 			      std_only = TRUE;
86 			      if (interactive && !quiet)
87 				{
88 				  show_bc_version ();
89 				  welcome ();
90 				}
91 			    }
92 			| program input_item
93 			;
94 input_item		: semicolon_list ENDOFLINE
95 			    { run_code (); }
96 			| function
97 			    { run_code (); }
98 			| error ENDOFLINE
99 			    {
100 			      yyerrok;
101 			      init_gen () ;
102 			    }
103 			;
104 semicolon_list		: /* empty */
105 			    { $$ = 0; }
106 			| statement_or_error
107 			| semicolon_list ';' statement_or_error
108 			| semicolon_list ';'
109 			;
110 statement_list		: /* empty */
111 			    { $$ = 0; }
112 			| statement
113 			| statement_list ENDOFLINE
114 			| statement_list ENDOFLINE statement
115 			| statement_list ';'
116 			| statement_list ';' statement
117 			;
118 statement_or_error	: statement
119 			| error statement
120 			    { $$ = $2; }
121 			;
122 statement 		: Warranty
123 			    { warranty ("s"); }
124 			| expression
125 			    {
126 			      if ($1 & 1)
127 				generate ("W");
128 			      else
129 				generate ("p");
130 			    }
131 			| STRING
132 			    {
133 			      $$ = 0;
134 			      generate ("w");
135 			      generate ($1);
136 			      free ($1);
137 			    }
138 			| Break
139 			    {
140 			      if (break_label == 0)
141 				yyerror ("Break outside a for/while");
142 			      else
143 				{
144 				  sprintf (genstr, "J%1d:", break_label);
145 				  generate (genstr);
146 				}
147 			    }
148 			| Quit
149 			    { bc_exit (0); }
150 			| Return
151 			    { generate ("0R"); }
152 			| Return '(' return_expression ')'
153 			    { generate ("R"); }
154 			| For
155 			    {
156 			      $1 = break_label;
157 			      break_label = next_label++;
158 			    }
159 			  '(' expression ';'
160 			    {
161 			      $4 = next_label++;
162 			      sprintf (genstr, "pN%1d:", $4);
163 			      generate (genstr);
164 			    }
165 			  relational_expression ';'
166 			    {
167 			      $7 = next_label++;
168 			      sprintf (genstr, "B%1d:J%1d:", $7, break_label);
169 			      generate (genstr);
170 			      $<i_value>$ = next_label++;
171 			      sprintf (genstr, "N%1d:", $<i_value>$);
172 			      generate (genstr);
173 			    }
174 			  expression ')'
175 			    {
176 			      sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
177 			      generate (genstr);
178 			    }
179 			  statement
180 			    {
181 			      sprintf (genstr, "J%1d:N%1d:", $<i_value>9,
182 				       break_label);
183 			      generate (genstr);
184 			      break_label = $1;
185 			    }
186 			| If '(' relational_expression ')'
187 			    {
188 			      $3 = next_label++;
189 			      sprintf (genstr, "Z%1d:", $3);
190 			      generate (genstr);
191 			    }
192 			  statement
193 			    {
194 			      sprintf (genstr, "N%1d:", $3);
195 			      generate (genstr);
196 			    }
197 			| While
198 			    {
199 			      $1 = next_label++;
200 			      sprintf (genstr, "N%1d:", $1);
201 			      generate (genstr);
202 			    }
203 			'(' relational_expression
204 			    {
205 			      $4 = break_label;
206 			      break_label = next_label++;
207 			      sprintf (genstr, "Z%1d:", break_label);
208 			      generate (genstr);
209 			    }
210 			')' statement
211 			    {
212 			      sprintf (genstr, "J%1d:N%1d:", $1, break_label);
213 			      generate (genstr);
214 			      break_label = $4;
215 			    }
216 			| '{' statement_list '}'
217 			    { $$ = 0; }
218 			;
219 function 		: Define NAME '(' opt_parameter_list ')' '{'
220        			  ENDOFLINE opt_auto_define_list
221 			    { char *params, *autos;
222 			      check_params ($4,$8);
223 			      params = arg_str ($4);
224 			      autos = arg_str ($8);
225 			      set_genstr_size (30 + strlen (params)
226 					       + strlen (autos));
227 			      sprintf (genstr, "F%d,%s.%s[", lookup ($2,FUNCT),
228 				       params, autos);
229 			      generate (genstr);
230 			      free_args ($4);
231 			      free_args ($8);
232 			      $1 = next_label;
233 			      next_label = 0;
234 			    }
235 			  statement_list ENDOFLINE '}'
236 			    {
237 			      generate ("0R]");
238 			      next_label = $1;
239 			    }
240 			;
241 opt_parameter_list	: /* empty */
242 			    { $$ = NULL; }
243 			| parameter_list
244 			;
245 parameter_list 		: NAME
246 			    { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE); }
247 			| define_list ',' NAME
248 			    { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
249 			;
250 opt_auto_define_list 	: /* empty */
251 			    { $$ = NULL; }
252 			| Auto define_list ENDOFLINE
253 			    { $$ = $2; }
254 			| Auto define_list ';'
255 			    { $$ = $2; }
256 			;
257 define_list 		: NAME
258 			    { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE); }
259 			| NAME '[' ']'
260 			    { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
261 			| define_list ',' NAME
262 			    { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
263 			| define_list ',' NAME '[' ']'
264 			    { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
265 			;
266 opt_argument_list	: /* empty */
267 			    { $$ = NULL; }
268 			| argument_list
269 			;
270 argument_list 		: expression
271 			    { $$ = nextarg (NULL,0, FALSE); }
272 			| argument_list ',' expression
273 			    { $$ = nextarg ($1,0, FALSE); }
274 			;
275 relational_expression	: expression
276 			    { $$ = 0; }
277 			| expression REL_OP expression
278 			    {
279 			      $$ = 0;
280 			      switch (*($2))
281 				{
282 				case '=':
283 				  generate ("=");
284 				  break;
285 				case '!':
286 				  generate ("#");
287 				  break;
288 				case '<':
289 				  if ($2[1] == '=')
290 				    generate ("{");
291 				  else
292 				    generate ("<");
293 				  break;
294 				case '>':
295 				  if ($2[1] == '=')
296 				    generate ("}");
297 				  else
298 				    generate (">");
299 				  break;
300 				}
301 			    }
302 			;
303 return_expression	: /* empty */
304 			    {
305 			      $$ = 0;
306 			      generate ("0");
307 			    }
308 			| expression
309 			;
310 expression		: named_expression ASSIGN_OP
311 			    {
312 			      if ($2 != '=')
313 				{
314 				  if ($1 < 0)
315 				    sprintf (genstr, "DL%d:", -$1);
316 				  else
317 				    sprintf (genstr, "l%d:", $1);
318 				  generate (genstr);
319 				}
320 			    }
321 			  expression
322 			    {
323 			      $$ = 0;
324 			      if ($2 != '=')
325 				{
326 				  sprintf (genstr, "%c", $2);
327 				  generate (genstr);
328 				}
329 			      if ($1 < 0)
330 				sprintf (genstr, "S%d:", -$1);
331 			      else
332 				sprintf (genstr, "s%d:", $1);
333 			      generate (genstr);
334 			    }
335 			| expression '+' expression
336 			    { generate ("+"); }
337 			| expression '-' expression
338 			    { generate ("-"); }
339 			| expression '*' expression
340 			    { generate ("*"); }
341 			| expression '/' expression
342 			    { generate ("/"); }
343 			| expression '%' expression
344 			    { generate ("%"); }
345 			| expression '^' expression
346 			    { generate ("^"); }
347 			| '-' expression           %prec UNARY_MINUS
348 			    { generate ("n"); $$ = 1;}
349 			| named_expression
350 			    {
351 			      $$ = 1;
352 			      if ($1 < 0)
353 				sprintf (genstr, "L%d:", -$1);
354 			      else
355 				sprintf (genstr, "l%d:", $1);
356 			      generate (genstr);
357 			    }
358 			| NUMBER
359 			    {
360 			      int len = strlen ($1);
361 			      $$ = 1;
362 			      if (len == 1 && *$1 == '0')
363 				generate ("0");
364 			      else
365 				{
366 				  if (len == 1 && *$1 == '1')
367 				    generate ("1");
368 				  else
369 				    {
370 				      generate ("K");
371 				      generate ($1);
372 				      generate (":");
373 				    }
374 				  free ($1);
375 				}
376 			    }
377 			| '(' expression ')'
378 			    { $$ = 1; }
379 			| NAME '(' opt_argument_list ')'
380 			    {
381 			      $$ = 1;
382 			      if ($3 != NULL)
383 				{ char *params = call_str ($3);
384 				  set_genstr_size (20 + strlen (params));
385 				  sprintf (genstr, "C%d,%s:",
386 					   lookup ($1,FUNCT), params);
387 				  free_args ($3);
388 				}
389 			      else
390 				  sprintf (genstr, "C%d:", lookup ($1,FUNCT));
391 			      generate (genstr);
392 			    }
393 			| INCR_DECR named_expression
394 			    {
395 			      $$ = 1;
396 			      if ($2 < 0)
397 				{
398 				  if ($1 == '+')
399 				    sprintf (genstr, "DA%d:L%d:", -$2, -$2);
400 				  else
401 				    sprintf (genstr, "DM%d:L%d:", -$2, -$2);
402 				}
403 			      else
404 				{
405 				  if ($1 == '+')
406 				    sprintf (genstr, "i%d:l%d:", $2, $2);
407 				  else
408 				    sprintf (genstr, "d%d:l%d:", $2, $2);
409 				}
410 			      generate (genstr);
411 			    }
412 			| named_expression INCR_DECR
413 			    {
414 			      $$ = 1;
415 			      if ($1 < 0)
416 				{
417 				  sprintf (genstr, "DL%d:x", -$1);
418 				  generate (genstr);
419 				  if ($2 == '+')
420 				    sprintf (genstr, "A%d:", -$1);
421 				  else
422 				    sprintf (genstr, "M%d:", -$1);
423 				}
424 			      else
425 				{
426 				  sprintf (genstr, "l%d:", $1);
427 				  generate (genstr);
428 				  if ($2 == '+')
429 				    sprintf (genstr, "i%d:", $1);
430 				  else
431 				    sprintf (genstr, "d%d:", $1);
432 				}
433 			      generate (genstr);
434 			    }
435 			| Length '(' expression ')'
436 			    { generate ("cL"); $$ = 1;}
437 			| Sqrt '(' expression ')'
438 			    { generate ("cR"); $$ = 1;}
439 			| Scale '(' expression ')'
440 			    { generate ("cS"); $$ = 1;}
441 			;
442 named_expression	: NAME
443 			    { $$ = lookup ($1,SIMPLE); }
444 			| NAME '[' expression ']'
445 			    { $$ = lookup ($1,ARRAY); }
446 			| Ibase
447 			    { $$ = 0; }
448 			| Obase
449 			    { $$ = 1; }
450 			| Scale
451 			    { $$ = 2; }
452 			;
453 
454 %%
455