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