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