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